<?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: Xebia Microsoft Services</title>
    <description>The latest articles on DEV Community by Xebia Microsoft Services (@xebia).</description>
    <link>https://dev.to/xebia</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%2Forganization%2Fprofile_image%2F1151%2Fa11d7ac2-38af-48a4-905d-4a17d8812df6.png</url>
      <title>DEV Community: Xebia Microsoft Services</title>
      <link>https://dev.to/xebia</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xebia"/>
    <language>en</language>
    <item>
      <title>Recommendations for using Azure CLI in your workflow</title>
      <dc:creator>Jesse Houwing</dc:creator>
      <pubDate>Mon, 27 Nov 2023 11:28:17 +0000</pubDate>
      <link>https://dev.to/xebia/recommendations-for-using-azure-cli-in-your-workflow-lh5</link>
      <guid>https://dev.to/xebia/recommendations-for-using-azure-cli-in-your-workflow-lh5</guid>
      <description>&lt;p&gt;Azure CLI is widely used in GitHub Actions and Azure Pipelines, as well as many other CI/CD tools. Over the last few weeks, I've been looking into its performance and security and based on that here are a number of recommendations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reduce azure-cli chattiness
&lt;/h2&gt;

&lt;p&gt;In its default configuration Azure CLI can be quite chatty, even accidentally echoing secrets to the console if you're not using it wisely. There are a number of settings you can apply to reduce the chattiness and by doing so automatically improve your security posture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az config set core.only_show_errors=true
az config set core.error_recommendation=off
az config set core.collect_telemetry=false
az config set logging.enable_log_file=false
az config set core.survey_message=false
az config set auto-upgrade.enable=false
az config set core.no_color=true
az config set extension.use_dynamic_install=false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most &lt;a href="https://learn.microsoft.com/en-us/cli/azure/azure-cli-configuration?ref=jessehouwing.net" rel="noopener noreferrer"&gt;switches are explained in the azure cli configuration&lt;/a&gt; docs. There is a module called &lt;code&gt;init&lt;/code&gt; that you can use to configure a number of these settings with ease (not all unfortunately):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; az extension add --name init
&amp;gt; az init

Select an option by typing its number

     [1] Optimize for interaction
         These settings improve the output legibility and optimize for human interaction

     [2] Optimize for automation
         These settings optimize for machine efficiency
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately, the &lt;code&gt;AzureCLI@2&lt;/code&gt; task in Azure Pipelines, by default, ignores the global configuration (see below), an even better &lt;strong&gt;way to set these options is through environment variables&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AZURE_CORE_ONLY_SHOW_ERRORS=TRUE
AZURE_CORE_ERROR_RECOMMENDATION=FALSE
AZURE_CORE_COLLECT_TELEMETRY=FALSE
AZURE_LOGGING_ENABLE_LOG_FILE=FALSE
AZURE_CORE_SURVEY_MESSAGE=FALSE
AZURE_AUTO-UPGRADE_ENABLE=FALSE
AZURE_CORE_NO_COLOR=TRUE
AZURE_EXTENSION_USE_DYNAMIC_INSTALL=FALSE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For self-hosted runners/agents you can either set these variables in the VMs global environment settings, or in the runner/agent's &lt;code&gt;.env&lt;/code&gt; file:&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%2Ffu14a4kxd81qqhm9r6e2.png" 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%2Ffu14a4kxd81qqhm9r6e2.png" alt="Recommendations for using Azure CLI in your workflow" width="677" height="285"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The .env file is stored in the runner/agent's root folder&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Be sure to restart the agent afterwards.&lt;/p&gt;

&lt;p&gt;Since workflow/pipeline variables are automatically lifted to environment variables, you can also define these in your workflow or in the repository settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Azure Pipelines
variables:
  AZURE_CORE_ONLY_SHOW_ERRORS=TRUE
  AZURE_CORE_ERROR_RECOMMENDATION=FALSE
  AZURE_CORE_COLLECT_TELEMETRY=FALSE
  AZURE_LOGGING_ENABLE_LOG_FILE=FALSE
  AZURE_CORE_SURVEY_MESSAGE=FALSE
  AZURE_AUTO-UPGRADE_ENABLE=FALSE
  AZURE_CORE_NO_COLOR=TRUE
  AZURE_EXTENSION_USE_DYNAMIC_INSTALL=FALSE

# GitHub Actions
env:
  AZURE_CORE_ONLY_SHOW_ERRORS=TRUE
  AZURE_CORE_ERROR_RECOMMENDATION=FALSE
  AZURE_CORE_COLLECT_TELEMETRY=FALSE
  AZURE_LOGGING_ENABLE_LOG_FILE=FALSE
  AZURE_CORE_SURVEY_MESSAGE=FALSE
  AZURE_AUTO-UPGRADE_ENABLE=FALSE
  AZURE_CORE_NO_COLOR=TRUE
  AZURE_EXTENSION_USE_DYNAMIC_INSTALL=FALSE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For GitHub Actions, you can import the env file to an organization level variable library in a single command with the github cli:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; gh variable set --env-file .env --organization myorg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Azure Pipelines, you can create a variable group and import that into every pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pwsh&amp;gt; az pipelines variable-group create --name azure-cli-default-settings --authorize --variables `
  AZURE_CORE_ONLY_SHOW_ERRORS=TRUE `
  AZURE_CORE_ERROR_RECOMMENDATION=FALSE `
  AZURE_CORE_COLLECT_TELEMETRY=FALSE `
  AZURE_LOGGING_ENABLE_LOG_FILE=FALSE `
  AZURE_CORE_SURVEY_MESSAGE=FALSE `
  AZURE_AUTO-UPGRADE_ENABLE=FALSE `
  AZURE_CORE_NO_COLOR=TRUE `
  AZURE_EXTENSION_USE_DYNAMIC_INSTALL=FALSE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  For security capture the output
&lt;/h2&gt;

&lt;p&gt;Some commands (such as reading appsettings) may return connection strings or passwords. You don't want these to end up in the logs. In addition to setting &lt;code&gt;core.only_show_errors=true&lt;/code&gt;, you can &lt;a href="https://www.paloaltonetworks.com/blog/prisma-cloud/secrets-leakage-user-error-azure-cli/?ref=jessehouwing.net" rel="noopener noreferrer"&gt;protect yourself further by redirecting the output from &lt;code&gt;az&lt;/code&gt; to a variable, &lt;code&gt;null&lt;/code&gt; or a file&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;# capture the result in a variable

$output = &amp;amp; az ...

# redirect output
&amp;amp; az ... &amp;gt; $null
&amp;amp; az ... 2&amp;gt;&amp;amp;1 &amp;gt; $null # incl the error stream for extra protection

# write output to a file
&amp;amp; az ... -o ./output.json
&amp;amp; az ... --output ./output.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mind the case
&lt;/h2&gt;

&lt;p&gt;While the Azure CLI accepts its commands and parameters in any case you use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚠️ Works, but don't do it
az CoNfIG SeT a=b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It greatly reduces the performance, especially on windows, due to the way the internal caching mechanism looks up the command implementations.&lt;/p&gt;

&lt;p&gt;Instead, pass all the commands and switches in &lt;strong&gt;lowercase&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✅ use lowercase for all commands and switches
az config set a=b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will save you precious time (about 10 seconds on Linux and up to a minute on Windows) every time you run &lt;code&gt;az&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the global configuration on Hosted Runners/Agents
&lt;/h2&gt;

&lt;p&gt;The Hosted Runners/Agents take great care to set-up and warm-up the Azure CLI to improve its performance, especially the first-run performance. It does so by setting the &lt;code&gt;AZURE_GLOBAL_CONFIG&lt;/code&gt; environment variable to a folder that has been prepped during the virtual machine image creation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not overwrite the &lt;code&gt;AZURE_GLOBAL_CONFIG&lt;/code&gt; variable in your own scripts.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;However&lt;/strong&gt; , on Azure Pipelines, the &lt;code&gt;AzureCLI@2&lt;/code&gt; task overwrites the &lt;code&gt;AZURE_GLOBAL_CONFIG&lt;/code&gt; variable and redirects it to the agent's temp directory.&lt;/p&gt;

&lt;p&gt;You can add a switch to the task to turn off this behavior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- task: AzureCLI@2
  inputs:
    useGlobalConfig: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was the default behavior in &lt;code&gt;AzureCLI@1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Using the global configuration will reduce the time needed to set-up the task by more than 1 minute on the Windows Hosted Runner/Agent and by about 10 seconds on Linux.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You might wonder why it doesn't use global config by default. The reason for this is to support multiple agents on the same VM calling &lt;code&gt;az&lt;/code&gt; at the same time. By redirecting the global config for each agent to its own temp directory they can't accidentally overwrite each other's settings or fight over file locks.  &lt;/p&gt;

&lt;p&gt;For self-hosted non-ephemeral runners/agents it also ensures that each job starts with a fresh set of settings as the temp folder is cleared before each run.  &lt;/p&gt;

&lt;p&gt;Since the hosted runners/agents don't run more than one job in parallel and always start with a fresh VM, there is no need to perform this redirection.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;az devops&lt;/code&gt;: Don't rely on auto-discover for speed
&lt;/h2&gt;

&lt;p&gt;The Azure DevOps extension for Azure CLI offers an auto-discover option which uses the git repository's remote to automatically identify the Azure DevOps organization and project. While super convenient, it takes time to look up this information each time you run &lt;code&gt;az devops&lt;/code&gt; or a related command.&lt;/p&gt;

&lt;p&gt;Instead, pass the &lt;code&gt;--organization&lt;/code&gt; and &lt;code&gt;--project&lt;/code&gt; settings explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- pwsh: |
    az pipelines show --organization=$env:SYSTEM_COLLECTIONURI --project=$env:SYSTEM_TEAMPROJECT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or set them once as defaults at the start of your workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- pwsh: |
    az devops configure --defaults organization=$env:SYSTEM_COLLECTIONURI project=$env:SYSTEM_TEAMPROJECT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;code&gt;az devops&lt;/code&gt;: Don't use &lt;code&gt;AzureCLI@2&lt;/code&gt;, use standard shell instead
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;AzureCLI@2&lt;/code&gt; task does a number of setup steps, authenticates to Azure, redirects the global configuration folder, does an update-check... But if you only need to run &lt;code&gt;az devops&lt;/code&gt; commands, then you don't need any of that.&lt;/p&gt;

&lt;p&gt;In that case you can use the standard scripting features of Azure Pipelines such as &lt;code&gt;script:&lt;/code&gt; and &lt;code&gt;pwsh:&lt;/code&gt; or &lt;code&gt;- task: Bash@2&lt;/code&gt; or &lt;code&gt;- task: PowerShell@2&lt;/code&gt; to gain a massive performance boost.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;az devops&lt;/code&gt;: Use environment variable for authentication in Azure Pipelines
&lt;/h2&gt;

&lt;p&gt;When you're using the &lt;code&gt;az devops&lt;/code&gt; extension, you can authenticate in 3 ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;az login&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;az devops login&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;environment variable&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since Azure Pipelines already holds an authentication token in its environment, the fastest way to authenticate is to leverage that token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- pwsh: |
      az pipelines list --organization=$env:SYSTEM_COLLECTIONURI --project=$env:SYSTEM_TEAMPROJECT
  env:
    AZURE_DEVOPS_EXT_PAT: $(System.AccessToken)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You do have to pass the token explicitly, because Azure Pipelines won't pass secrets to tasks by default.&lt;/p&gt;

</description>
      <category>azurepipelines</category>
      <category>github</category>
      <category>githubactions</category>
      <category>azurecli</category>
    </item>
    <item>
      <title>Reflections of a DevOpsologist</title>
      <dc:creator>Arjan van Bekkum</dc:creator>
      <pubDate>Tue, 14 Nov 2023 08:17:29 +0000</pubDate>
      <link>https://dev.to/xebia/reflections-of-a-devopsologist-3l4i</link>
      <guid>https://dev.to/xebia/reflections-of-a-devopsologist-3l4i</guid>
      <description>&lt;p&gt;Author: Colin Dembovsky&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“DevOps is the union of people, processes and products to enable continuous delivery of value to our end users.” &lt;em&gt;Donovan Brown&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At heart, I’m a developer. I love to sling code and be part of a team that slings code. But I’m also fascinated by &lt;em&gt;people&lt;/em&gt; – and the intersection of culture and tech is what has drawn me to DevOps.&lt;/p&gt;

&lt;p&gt;As I reflect over my journey, I see a lot of people who invested in me. Without them I would not be where I am today. Quite literally – I am an immigrant to the US and my career brought me here. I’ve also worked hard when opportunity presented itself. I’ve been mentored and have mentored others. I have learned some things along the way that I hope I can communicate through my story.&lt;/p&gt;

&lt;p&gt;But wait – before I start: what is a DevOpsologist? I forget where I heard the term from (it’s not mine) but I love the sentiment. It comes from DevOps and the suffix “-ology” (the study of something, a branch of learning). DevOps is continually evolving and changing, and I don’t think we’ll ever “arrive”. Calling myself a DevOpsologist reminds me that there is always more to learn!&lt;/p&gt;

&lt;h1&gt;
  
  
  The Story
&lt;/h1&gt;

&lt;h2&gt;
  
  
  The Journey Begins
&lt;/h2&gt;

&lt;p&gt;It was summer (at least in the Southern hemisphere) of 2004. I had just moved from Johannesburg to East London, South Africa where I joined a team of about 20 developers for a financial services company. I had been hired on as a senior developer – and little did I know that the next six years would come to define so much of my career.&lt;/p&gt;

&lt;p&gt;I was now about three months into the job. My previous job hadn’t been anywhere close to anything from Microsoft. It was all C++, &lt;a href="https://en.wikipedia.org/wiki/Common_Object_Request_Broker_Architecture"&gt;CORBA&lt;/a&gt; and Linux. Now here I was, a senior developer at a team using SQL Server and Web services built on .NET Framework 1.1. I had used CVS for source control before, and the new team was using WinCVS. It wasn’t pretty. There was almost no process in place – we deployed by using Visual Studio’s “right-click Publish” feature and fat-fingering was so common it was expected.&lt;/p&gt;

&lt;p&gt;I remember thinking to myself, “I may not be the most experienced .NET developer, but there must be a better way to manage how we deliver code.” So I opened up a browser and used my favorite search engine, WebCrawler, to see if I could find anything better.&lt;/p&gt;

&lt;p&gt;And I did. I found a tool that was so new it was still in beta. The installation took about a week – at one point the install failed and I couldn’t recover. In fact, the failure was so bad I ended up formatting the entire machine and starting again. But I persisted – and finally stood up a shiny new instance of Team Foundation Server (TFS) 2005 beta 2.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Glorious TFS Days
&lt;/h2&gt;

&lt;p&gt;So began my journey into DevOps. Except that the term DevOps hadn’t been coined yet. It was still “Application Lifecycle Management” (ALM). I don’t even think I heard that term until around 2008. But even if I didn’t know what it was called, I was doing it. Mostly by instinct.&lt;/p&gt;

&lt;p&gt;We started by getting all of our code into TFS. We even started using automated builds with MSBuild! We could at least build from a known source of truth, rather than hoping what we had on our dev machines was the latest code.&lt;/p&gt;

&lt;p&gt;Our next phase was adopting unit testing. I remember some very heated debates with the team. “We have too much code and our coverage will be practically zero!” was a common sentiment. I managed to convince the team that 0.2% code coverage is better than 0%, so we started by just ensuring that if we touched a method (or added one) that we would only deploy if we had a unit test for that changed code. Before long, we were in the 60% range for code coverage. Small, incremental changes added up having a large impact over time.&lt;/p&gt;

&lt;p&gt;We also started using Work Item Tracking. We all underwent Prince2 training (it’s a flavor of Waterfall from the British Government) and customized our templates, work items and reports to match. Back then we had to create our own Release Management tool since there wasn’t one in TFS till years later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Jump to Consulting
&lt;/h2&gt;

&lt;p&gt;In 2008, I attended TechEd Africa in Durban, South Africa. This was my first large tech conference experience. I went to a talk by Chris Menegay, who ran a small consulting firm in Dallas, Texas called Notion Solutions. Chris had an ALM talk that featured TFS. I knew I wanted to move into consulting at some stage, but until that point I had no idea what to consult in! Hearing Chris talk about his team of ALM consultants, I knew that was what I wanted to do. However, my first child had just been born, and I didn’t think it was the right time to leave a job with a steady salary.&lt;/p&gt;

&lt;p&gt;I attended TechEd Africa in 2009 – and Chris was a guest speaker again! This time I was ready for a change – so after his talk, I had a 5 minute conversation with him. I remember asking him if he did any work in South Africa, and he replied he could send a consultant over (later I found out he was thinking of Donovan Brown who worked for Chris at that stage). “No, I’m looking to get into consulting,” I responded. Chris and I had a chat with a key Microsoft figure – and someone I owe a debt to for all the help in my early days – Ahmed Salijee, who headed up Visual Studio sales for Microsoft in South Africa.&lt;/p&gt;

&lt;p&gt;For some reason, Chris took a chance on me – and a few months later I started the South Africa branch of Notion Solutions! Chris put a few thousand dollars in so I had a steady salary, but I did everything. I was calling. I was delivering. I was invoicing – I learned so much during that time. Fortunately, I had the collective minds of Notion Solutions backing me, so I started confidently, even though I didn’t really know what I was doing. That was a good way to grow.&lt;/p&gt;

&lt;h2&gt;
  
  
  How did I get here?
&lt;/h2&gt;

&lt;p&gt;In September 2010 Chris flew me out to a Notion Solutions gathering in Irving, Texas. It was a rare occasion to have all the Notion Consultants in a single place. I remember feeling awed. There I was in the same room as some of my “ALM heroes” such as Chris Menegay, Dave McKinstry, Abel Wang, Donovan Brown, Steve St. Jean and Ed Blankenship. “How did I get here?” I wondered – but I was determined that I would learn all I could from these folks and wouldn’t take my good fortune for granted!&lt;/p&gt;

&lt;p&gt;Most of the Notion Team were Microsoft Most Valuable Professionals (MVPs) and I was inspired to attain that award too. So I started my blog – &lt;a href="https://colinsalmcorner.com"&gt;Colin’s ALM Corner&lt;/a&gt; which is still going today. In 2011, I was awarded my first MVP award. In 2012, I got to attend my first MVP Summit in Redmond, WA. There I met some folks that I am still connected to this day – leaders in the ALM community such as Marcel de Vries, René van Osnabrugge, Pieter Gheysens, Brian Randell, Nino Loje, Mickey Gousset, Esteban Garcia, Martin Hinshelwood and many others – including Steven Borg.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving to America
&lt;/h2&gt;

&lt;p&gt;Steve and I connected really well – and eventually he offered me a position at his company Northwest Cadence. Northwest Cadence was based in Seattle and was also a small ALM consultancy. Northwest Cadence persevered through all the legal processes to move me and my family over to Seattle in 2016, and I’ve been in the US since.&lt;/p&gt;

&lt;p&gt;Steve inspired me – he is an excellent communicator who knows something about everything. And his mastery of lean processes and agile was amazing. I remember thinking, “When I grow up, I want to be just like Steve!” I learned so much during my Northwest Cadence days, and still think in terms of flow, efficiency and queuing theory.&lt;/p&gt;

&lt;p&gt;In 2018, Steve merged his company into Chicago-based 10th Magnitude. 10th Magnitude was doing some great Azure work, but was finding more and more customers wanted to modernize their software processes as they migrated their data centers to the cloud. The folks from Northwest Cadence brought a wealth of process consulting and DevOps to 10th Magnitude, so it was a really good fit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving into… sales?
&lt;/h2&gt;

&lt;p&gt;Soon after joining 10th Magnitude, there was an opening for a Solution Architect. I looked at the position and chatted to a few folks, and discovered it was a technical sales role. “I’m not a salesman, I’m a consultant!” was my initial reaction. However, I negotiated with the leadership and took the role on the basis that I would sell for 30% of the time, and consult for the other 70%.&lt;/p&gt;

&lt;p&gt;That never turned out to be the case. I ended up selling far more than consulting. But one day I had an epiphany: I love to solve complex problems. And I was doing that in my sales process! I would meet with customers, and spend time to understand their environments, people and challenges. I then crafted services and deals that we would deliver to our customers to help them achieve their goals. While I was now in a sales role, I was able to do what I love doing – use tech and cultural engineering to solve problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is this Git thing?
&lt;/h2&gt;

&lt;p&gt;I remember when TFS introduced Git repositories around 2013. I couldn’t see the appeal – who would use a source control system that let you overwrite history? However, after spending some time with it I started to see the light – so much so that I did a talk at VSLive for a couple of years where I hypothesized that you can’t really do modern development if you’re &lt;em&gt;not&lt;/em&gt; on Git!&lt;/p&gt;

&lt;p&gt;And then – Microsoft purchased GitHub in 2018. So – reluctantly – I started to figure out how to use the platform. I preferred Team Foundation Server – which had changed names a couple of times and is now Azure DevOps. That is, until GitHub released GitHub Advanced Security (GHAS).&lt;/p&gt;

&lt;h2&gt;
  
  
  AppSec is the Future
&lt;/h2&gt;

&lt;p&gt;I have a development background – Security was always the team that “prevented you going to prod”. I didn’t speak security, and I had never met a security professional that spoke developer.&lt;/p&gt;

&lt;p&gt;But GHAS was different. I instinctively guessed that this was a tool that I wanted to align with. Over time, I was able to verbalize this instinctive feeling – it’s simply &lt;em&gt;security tools for developers&lt;/em&gt;. I recognized that this was a game-changer.&lt;/p&gt;

&lt;p&gt;At this stage I was the DevOps Practice lead at 10th Magnitude, and I created one of the first GHAS partner offerings. We had a 2-week GHAS Adoption service and were able to help onboard a few companies to GHAS in the early days.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving to GitHub
&lt;/h2&gt;

&lt;p&gt;I also got to deliver some GitHub/10th Magnitude Roadshows. I met a few Hubbers during that time – including Kevin Alwell, a Solution Engineer on the east coast. In 2021, I applied for a Solution Engineering position at GitHub – and about two days later, Kevin called me out of the blue. After catching up, he told me there was a Solution Engineer role he thought I would be good for… and the rest, as they say, is history.&lt;/p&gt;

&lt;h1&gt;
  
  
  Reflections
&lt;/h1&gt;

&lt;p&gt;I’ve had an incredible journey – and still have lots to look forward to! The advent of generative AI through ChatGPT and GitHub Copilot is just beginning to revolutionize development as we know it. If software has eaten the world, it’s now AI’s turn!&lt;/p&gt;

&lt;p&gt;Since I am a self-confessed DevOpsologist, I proclaim to be constantly learning. So what have I learned over the years working in DevOps?&lt;/p&gt;

&lt;h2&gt;
  
  
  Find your inspiration outside of your career
&lt;/h2&gt;

&lt;p&gt;My faith and my family are the core of my identity. I love being an SE and a technologist – but that’s what I do, not really who I am. This has been vital to handling pressure and hard times – when work sucks (as it inevitably will be from time to time), I don’t feel that &lt;em&gt;I suck&lt;/em&gt;. I’ve found that, ironically, living for something &lt;em&gt;other&lt;/em&gt; than work and technology has led to more fulfillment in work and tech! So find something that you can be passionate about that isn’t your work – and your work will actually improve!&lt;/p&gt;

&lt;h2&gt;
  
  
  People matter
&lt;/h2&gt;

&lt;p&gt;I love to sling code. I love being a geek. But no matter how technically proficient I am, and no matter how amazing the tech is, people are still the heart of DevOps. I see a lot of companies that fail not because they are not smart, and not because they have the wrong tools, but because they don’t prioritize people and culture.&lt;/p&gt;

&lt;p&gt;One of my favorite Laws is Conway’s Law. Conway (a programmer) introduced an idea in 1967 that showed a “homomorphic force” between the communication structure of a company and the architectures it produced. In other words, the culture plays a vital role in shaping the technology.&lt;/p&gt;

&lt;p&gt;If you haven’t yet read &lt;a href="https://teamtopologies.com/"&gt;Team Topologies&lt;/a&gt; do yourself a favor. Stop debating if you should implement microservices and spend some cycles on designing your &lt;em&gt;Teams&lt;/em&gt;. In other words, people matter – so align with that force so that you’re not fighting it all the time.&lt;/p&gt;

&lt;p&gt;I have had to learn (and still am learning) that &lt;em&gt;how&lt;/em&gt; you say something is just as important as &lt;em&gt;what&lt;/em&gt; you say. This was something I had to learn as a consultant – and I still have to work on it every day. I can come off as cutting and dismissive – a byproduct of my wiring to see to the heart of a problem very quickly. But I have to constantly think about how I communicate what I see. Because people matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stay teachable
&lt;/h2&gt;

&lt;p&gt;A corollary of the above is that &lt;em&gt;you matter&lt;/em&gt;. And if you matter, then you’re worth investing in. One of the best ways to invest in yourself is to ask for feedback (or consider unsolicited feedback carefully). We all have blind spots, biases and areas we can grow in. If you are not able to admit when you are wrong – and learn and grow – then you’re going to cap your potential.&lt;/p&gt;

&lt;p&gt;Managers, peers and customers have all at some time or other given me feedback about something. Each time I try to figure out what I can learn from that feedback. At times, I have “chewed the meat and spat out the bones”. Not all feedback is always correct – so I try to find the things that I can learn and grow from – and ignore the rest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep learning
&lt;/h2&gt;

&lt;p&gt;This is a core strength of mine (from &lt;a href="https://www.gallup.com/cliftonstrengths/en/strengthsfinder.aspx"&gt;Gallup’s CliftonStrenths&lt;/a&gt;). So learning comes easily to me – that’s not the case for everyone. But I believe that everyone should always be learning. And it’s close to being a requirement in DevOps given the pace of the software industry.&lt;/p&gt;

&lt;p&gt;I could have ignored GitHub Advanced Security – after all, I’m not a security professional. However, I applied myself to learn about it – and it’s been key to my success in the past few years. Sometimes, you’ll need to just knuckle down and learn about something even if it’s not “in your lane” – you’ll be surprised at what might happen!&lt;/p&gt;

&lt;h2&gt;
  
  
  Take calculated risks
&lt;/h2&gt;

&lt;p&gt;I didn’t know if consulting would be a good long-term choice for my career. I didn’t know if moving to the US would be good for my family. I didn’t know if moving into sales would be something I could do long-term. I approached each decision as rationally as I could, seeking input from friends, family, peers and managers as appropriate. But I never let myself get into “analysis paralysis”. At some point, I had to take some calculated risks. Thankfully, I’ve had a good run, even when there was uncertainty.&lt;/p&gt;

&lt;h1&gt;
  
  
  In closing
&lt;/h1&gt;

&lt;p&gt;Being in DevOps has been incredibly fulfilling – from the work I’ve been able to do, to the people I’ve met, to the ways I’ve grown and developed as a person. Every day I count myself fortunate to have a job I love – and to be in an industry that’s continuously changing and evolving. I hope that my story and some of my learnings can inspire you to keep growing – and hopefully, I get to hear your story some day.&lt;/p&gt;

&lt;p&gt;This article is part of XPRT. Magazine #15&lt;br&gt;&lt;br&gt;
&lt;a href="https://xpirit.com/xprt-magazine-n-15/"&gt;Download here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VRGEAVGU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xpirit.com/wp-content/uploads/2023/10/Xebia_Xpirit_XPRT_15_mockup-3-600x400.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VRGEAVGU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xpirit.com/wp-content/uploads/2023/10/Xebia_Xpirit_XPRT_15_mockup-3-600x400.png" alt="XPRT magazine 15" width="600" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://xpirit.com/reflections-of-a-devopsologist/"&gt;Reflections of a DevOpsologist&lt;/a&gt; appeared first on &lt;a href="https://xpirit.com"&gt;Xebia | Xpirit&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>github</category>
    </item>
    <item>
      <title>Securing Azure Service Bus</title>
      <dc:creator>Arjan van Bekkum</dc:creator>
      <pubDate>Thu, 02 Nov 2023 00:00:01 +0000</pubDate>
      <link>https://dev.to/xebia/securing-azure-service-bus-1mka</link>
      <guid>https://dev.to/xebia/securing-azure-service-bus-1mka</guid>
      <description>&lt;p&gt;Author: Olena Borzenko&lt;/p&gt;

&lt;p&gt;Security should be considered from the initial stages of designing a product rather than as an afterthought. This is particularly important for Service Bus as it often forms a part of a larger system. Security requirements may vary depending on the use case; for instance, a banking solution would have different security needs compared to a solution for a local bakery.&lt;/p&gt;

&lt;p&gt;Let’s examine common security risks, understand the importance of data encryption and various robust authentication methods such as Azure AD and shared access signatures, explore strategies for network protection, and emphasize the value of logging for enhanced oversight.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Protection and Risks
&lt;/h2&gt;

&lt;p&gt;The sensitivity or potential impact of a data leak may be high when transmitting data via Service Bus, particularly if it involves financial transactions, medical records, or sensitive personal information. It is crucial to protect the data from risks such as data exfiltration, unauthorized data movements, and unauthorized access. It is also important to have proper logging to monitor what is happening with the data.&lt;/p&gt;

&lt;p&gt;Service Bus performs &lt;em&gt;encryption in transit&lt;/em&gt;, or in other words, it ensures that data is encrypted while being transmitted. This includes encryption when data is moving from the client to Service Bus, within Service Bus, and from Service Bus to the consumer. By default, Azure Service Bus supports TLS 1.2 protocol on public endpoints. Initially, it was TLS 1.0, but due to customer demands for higher security, it now defaults to the higher version. However, this doesn’t mean that versions 1.0 and 1.1 are deprecated; they are still supported for backward compatibility, and users can set a minimum TLS version in their namespace. During other exchanges, secure protocols like HTTPS for straightforward RESTful operations and AMQP for efficient message queuing are used.&lt;/p&gt;

&lt;p&gt;Besides encryption in transit, Service Bus also performs &lt;em&gt;encryption at rest&lt;/em&gt;, meaning messages are encrypted while they are at rest (stored). This process is done automatically, and users don’t have to do anything to enable it. The encryption uses Azure storage encryption, and Service Bus is transitioning to service fabric storage for improved performance and cost savings.&lt;/p&gt;

&lt;p&gt;But what if the built-in security layers are not sufficient to meet customer requirements? In such cases, users can enhance security by bringing their own encryption key, stored in Azure Key Vault — a method commonly referred to as &lt;em&gt;BYOK (Bring Your Own Key)&lt;/em&gt;. The provided key can be used to encrypt data, adding an extra layer of security. This is particularly important for organizations with stringent security policies.&lt;/p&gt;

&lt;p&gt;So far we’ve examined some built-in security features as well as the method of introducing an extra layer of protection using the BYOK approach. There are also actions that can be taken on the client side for more advanced scenarios.&lt;/p&gt;

&lt;p&gt;For example, an additional layer of encryption can be implemented by the client, an approach we can refer to as &lt;em&gt;client-side encryption&lt;/em&gt;. The data protection step is performed before sending the data to Service Bus. While this is the most secure method, it also requires the most effort, as the client is responsible for both encryption and decryption. This approach is commonly used in highly sensitive environments like healthcare, where data breaches can have significant consequences.&lt;/p&gt;

&lt;p&gt;As we can see, there are many different mechanisms to secure our data. For maximum security, we can go a step further and opt for &lt;em&gt;multi-layer encryption&lt;/em&gt;. By combining client-side encryption, bringing your own key, and the platform encryption provided by Service Bus, we can achieve the highest level of data protection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication methods
&lt;/h2&gt;

&lt;p&gt;As previously mentioned, Azure Service Bus offers two types of authentication: &lt;em&gt;Azure Active Directory (Azure AD)&lt;/em&gt; and &lt;em&gt;Shared Access Signatures (SAS) keys&lt;/em&gt;. Let’s take a brief overview of these two types to understand what might be more suitable for certain needs.&lt;/p&gt;

&lt;p&gt;As a more modern and recommended form of authentication, Azure Active Directory (Azure AD) offers a range of features that enhance security and ease of management. It supports various types of accounts, service principals and provides a streamlined and secure method for managing identities. Its flexibility makes it easier to manage access for different clients or customers. For those looking to further tighten security, it’s possible to disable SAS authentication entirely and rely solely on Azure AD. Additionally, custom roles can be created to offer more granular permissions, allowing for tailored access control based on specific needs.&lt;/p&gt;

&lt;p&gt;Another robust authentication option, known as Shared Access Signatures (SAS) keys, involves generating a connection string from primary and secondary keys for authentication. These keys can be set at different scopes — namespace, topic, or queue — to allow fine-grained access control. To serve various consumers or users you can also create multiple keys but it’s important to note that &lt;strong&gt;they are static and require manual rotation&lt;/strong&gt; for enhanced security, especially the root manager key that controls the entire namespace. For extra security, using a token provider, such as an API that issues authentication tokens, is recommended over direct key usage. Although SAS are somewhat dated, they remain supported and are useful for systems restricted to this authentication method.&lt;/p&gt;

&lt;h2&gt;
  
  
  Network-level security
&lt;/h2&gt;

&lt;p&gt;Having explored data protection measures and authentication methods, let’s now turn our attention to another crucial aspect of securing Azure Service Bus: &lt;em&gt;network-level security&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;One effective measure is to set &lt;em&gt;Service Tags&lt;/em&gt; on the Service Bus namespace, which allows you to specify which Azure services can access your Service Bus. Additionally, IP Filtering can be employed to limit access to specific IP addresses or ranges. For those using the premium tier of Service Bus, adding the Service Bus to a Virtual Network can further minimize the attack surface.&lt;/p&gt;

&lt;p&gt;It’s worth mentioning that Service Bus is a foundational element of Azure’s architecture and offers tier-specific features. For instance, the premium tier provides advanced options like VNet integration, mainly because it operates on a dedicated resource model, unlike the standard tier.&lt;/p&gt;

&lt;p&gt;Who knows, maybe in the future the gap between the two tiers will be bridged to some extent. But for now, this gap results in a significant price difference between the standard and premium plans. Despite the use of dedicated hardware resources like virtual machines in the premium service, efforts are underway to narrow this price difference and make the subscription more accessible and affordable. Additionally, guidance and templates may be introduced to help determine the continuous need for the service or its occasional use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logging and monitoring for security and system health
&lt;/h2&gt;

&lt;p&gt;As we conclude our comprehensive exploration of Azure Service Bus security, let’s delve into the indispensable aspects of logging and monitoring for both security and overall system health.&lt;/p&gt;

&lt;p&gt;Service Bus generates a significant amount of logs, accessible through Application Insights and Log Analytics. The Kusto Query Language (KQL) is particularly useful for those who wish to work with these logs, as they include information about messages sent, connections made, and operations performed.&lt;/p&gt;

&lt;p&gt;There is also support for Azure Policy, which allows users to set policies for various configurations. For example, a user can set a minimum TLS version across all subscriptions to ensure that security standards are met. This helps ensure that everyone adheres to the same security principles.&lt;/p&gt;

&lt;p&gt;It is important to not only log information but also to actively monitor it for anomalies or issues. Service Bus allows users to set up alerts based on certain conditions or dynamic thresholds. For instance, if there is an unusual spike in connections, an alert can be triggered. This proactive monitoring is crucial, especially for those on duty, to quickly identify and address issues.&lt;/p&gt;

&lt;p&gt;Through Azure Monitor, users can integrate with other services such as Logic Apps or Azure Functions. Some companies have automated their workflow such that when an alert is triggered, the system analyzes what’s happening, assigns it to the correct team, sets a priority, and creates a ticket. This streamlines the process and ensures that the right people can start working on the issue promptly.&lt;/p&gt;

&lt;p&gt;In summary, the level of security implementation should be tailored to the specific scenario, taking into account the criticality of the data and operations involved. For instance, a small customer sending a few messages may not need the same robust measures as a large organization handling sensitive data. Alongside this, configuring encryption is a pivotal step, with options like client-side encryption providing added assurance by keeping keys on-premises. While Azure is compliant with GDPR and other standards, it’s essential to verify these, especially when dealing with sensitive information.&lt;/p&gt;

&lt;p&gt;This article is part of XPRT. Magazine #15&lt;br&gt;&lt;br&gt;
&lt;a href="https://xpirit.com/xprt-magazine-n-15/"&gt;Download here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VRGEAVGU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xpirit.com/wp-content/uploads/2023/10/Xebia_Xpirit_XPRT_15_mockup-3-600x400.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VRGEAVGU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xpirit.com/wp-content/uploads/2023/10/Xebia_Xpirit_XPRT_15_mockup-3-600x400.png" alt="XPRT magazine 15" width="600" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://xpirit.com/securing-azure-service-bus/"&gt;Securing Azure Service Bus&lt;/a&gt; appeared first on &lt;a href="https://xpirit.com"&gt;Xebia | Xpirit&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>security</category>
    </item>
    <item>
      <title>InnerSource</title>
      <dc:creator>Arjan van Bekkum</dc:creator>
      <pubDate>Mon, 30 Oct 2023 14:40:19 +0000</pubDate>
      <link>https://dev.to/xebia/innersource-254g</link>
      <guid>https://dev.to/xebia/innersource-254g</guid>
      <description>&lt;p&gt;Authors: Jasper Gilhuis &amp;amp; Arjan van Bekkum&lt;/p&gt;

&lt;h3&gt;
  
  
  Is InnerSource written weird?
&lt;/h3&gt;

&lt;p&gt;You will find a few related hits in Google if you search for "Inner Source", but back in the early days, no related hits where found. So, it was decided to call it InnerSource to get better reach!`&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What is InnerSource?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;InnerSource can be defined as the application of open-source software development principles within an organization’s internal software development processes. It draws on the valuable lessons learned from open-source projects and adapts them to the context of how companies create software internally.&lt;/p&gt;

&lt;p&gt;Similar to the familiarity of “Open Source”, InnerSource encourages collaboration within the confines of an organization. It entails leveraging publicly available software, often used by developers in their daily work, and allows for feedback, including requests for new features, bug fixes, and changes, fostering collaboration akin to open-source projects.&lt;/p&gt;

&lt;p&gt;InnerSource operates on four core principles, briefly summarized here, with more details available at &lt;a href="https://innersourcecommons.org"&gt;InnerSource Commons&lt;/a&gt;. InnerSource Commons is a community-driven organization that aims to promote and facilitate the adoption of InnerSource practices to improve software development within organizations. It provides a platform for knowledge sharing, collaboration, and the development of valuable resources for the InnerSource community.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Openness:&lt;/strong&gt; Openness in InnerSource projects ensures accessibility and simplifies contributions. It involves well-documented projects, making it easy for anyone within the organization to discover, understand, and participate. Host team contact information is readily accessible, and intentions to accept InnerSource contributions are communicated through relevant channels, promoting successful collaboration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transparency:&lt;/strong&gt; Transparency is fundamental for effective InnerSource collaboration. Host teams must provide clear insights into the project’s direction, requirements, progress, and decision-making processes. Communication should be detailed and accessible to individuals beyond the core team, facilitating contributions from guest teams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prioritized Mentorship:&lt;/strong&gt; InnerSource relies on mentorship from host teams to guest teams, guided by trusted committers. This mentorship elevates contributors on guest teams, enabling them to engage with and modify host team projects effectively. Host teams should prioritize mentorship, assisting guest team contributors when needed, and fostering beneficial relationships within the organization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Voluntary Code Contribution:&lt;/strong&gt; InnerSource thrives on voluntary participation, where guest and host teams engage willingly. Guest teams contribute code to host teams and accept these contributions voluntarily. This voluntary approach ensures alignment with each team’s objectives, allowing host teams to accept contributions that align with their mission and guest teams to prioritize contributions that serve their goals. Full collaboration extends to code contributions to maximize InnerSource’s benefits.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why InnerSource and the Problems It Solves&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When adopting InnerSource within your organization, defining your goals and understanding what problems it can address is essential. Clarity in your objectives helps people relate to and engage with InnerSource effectively.&lt;/p&gt;

&lt;p&gt;Are you aiming to improve Developer Velocity, as measured by the Developer Velocity Index (DVI) (1), which correlates with faster revenue growth, higher shareholder returns, increased innovation, and improved customer satisfaction? Alternatively, are you fostering a collaboration mindset, emphasizing knowledge sharing and collaboration? Perhaps your focus is on breaking down traditional boundaries through DevOps practices. Identifying your true north star for InnerSource enables you to tailor its implementation to address specific challenges and objectives within your organization.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Benefits of InnerSource&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The advantages of adopting InnerSource are substantial and include:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Mitigating Inter-Team Dependencies:&lt;/strong&gt; When teams operate in isolation, working solely on their individual “projects” or “repositories” without sharing their work, it often leads to code duplication across multiple areas. This results in wasted effort as people tackle the same problems independently and can also introduce subtle variations in behavior for identical solutions. InnerSource promotes knowledge sharing and collaboration on shared solutions, significantly reducing code redundancy and enhancing efficiency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Resolving Dependencies Effectively:&lt;/strong&gt; In larger organizations, there’s typically a constant struggle for resource allocation and prioritization. This often leads to battles outside of the team’s immediate focus. InnerSource helps by providing teams with visibility into available software resources and contacts within the organization. This transparency enables teams to collaborate on improving code or adding new features, all with the approval of the original owners, without waiting for prioritization decisions. While it requires some initial coordination, it is often more time-efficient than waiting for prioritization decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Interaction Model&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;As we are building communities around projects you can clearly see communication is key. In this asynchronous world, let alone timezone differences and cross-organization collaboration, it is obvious that you need to set up your guidance in a clear and easy-to-find way. GitHub provides a comprehensive set of documented principles and practices to assist you in getting started with community collaboration. These resources cover various aspects, from establishing code of conduct guidelines and creating community profiles to utilizing pull request templates. Additionally, GitHub offers a range of communication tools to support effective collaboration within your community. You can access these valuable resources at &lt;a href="https://docs.github.com/en/communities"&gt;https://docs.github.com/en/communities&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--77XxFwLN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xpirit.com/wp-content/uploads/2023/10/role_overview-600x273.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--77XxFwLN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xpirit.com/wp-content/uploads/2023/10/role_overview-600x273.png" alt="InnerSource" width="600" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Product Team:&lt;/strong&gt; The original product team plays a pivotal role in the development and upkeep of the core project. They are the primary decision-makers, determining which contributions to accept or reject. Additionally, they provide valuable guidance and mentorship to external contributors, ensuring the project’s alignment with its goals and maintaining its overall quality.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Product Owner:&lt;/strong&gt; The product owner defines the project’s overarching vision, goals, and priorities. Collaborating closely with the original product team ensures that contributions harmonize with the project’s objectives. Often, they prioritize specific features or enhancements based on user needs and market demands.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trusted Committers:&lt;/strong&gt; Trusted committers are individuals or team members who understand the project and have earned the community’s trust. Their primary role involves reviewing and approving contributions from external contributors. Beyond this, they are crucial in mentoring and guiding contributors, ensuring the project’s ongoing quality and consistency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contributors:&lt;/strong&gt; Contributors are external individuals or teams that aim to make valuable contributions to the project. They actively submit code, bug fixes, or new features for review and integration into the project. Seeking feedback and collaboration within the project’s community, contributors drive the project’s evolution and improvement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consumers:&lt;/strong&gt; Consumers, which include end-users and stakeholders, are the beneficiaries of the project’s functionality. They utilize the project or product created through the collective efforts of the original product team, external contributors, and trusted committers. By leveraging these contributions, consumers meet their needs, provide usability feedback, and enjoy ongoing enhancements.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  InnerSource Patterns
&lt;/h2&gt;

&lt;p&gt;The InnerSource Patterns are a valuable resource that offers actionable insights and best practices for implementing InnerSource principles within an organization’s software development processes. These patterns serve as a roadmap to facilitate effective collaboration, knowledge sharing, and project contributions, mirroring the successful dynamics of open source communities. By harnessing these patterns, organizations can streamline their development workflows, cultivate a culture of transparency, and drive innovation through collective efforts. Each pattern provides a structured approach to address specific challenges, making the adoption of InnerSource a well-guided and efficient endeavor. You can explore these patterns in detail at &lt;a href="https://patterns.innersourcecommons.org/"&gt;InnerSource Commons Patterns&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One particularly noteworthy pattern that stands out in revolutionizing workplaces through InnerSource is the “Gig Marketplace” Pattern.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gig Marketplace Pattern
&lt;/h3&gt;

&lt;p&gt;The “Gig Marketplace” pattern is dedicated to dismantling organizational silos by establishing an internal marketplace for tasks or projects. This innovative approach empowers teams to collaborate with flexibility and efficiency, offering and requesting expertise or services across different departments. This pattern encourages the free flow of skills and resources, enabling teams to tackle challenges and complete projects swiftly while nurturing a culture of collaboration and knowledge exchange.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Areas to apply InnerSource&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Cloud Infrastructure&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The landscape of cloud architecture is evolving and growing increasingly intricate. Notably, many companies are witnessing the emergence of Cloud Centers of Excellence (CCoE). These entities primarily shoulder the responsibility of managing shared infrastructure within cloud environments. Beyond infrastructure management, they are vital in monitoring security and ensuring its continual upkeep. Within CCoEs, teams specializing in these tasks are commonly called platform teams.&lt;/p&gt;

&lt;p&gt;Modern cloud infrastructures often follow the hub and spoke model, exemplified by Microsoft’s Cloud Adoption Framework (CAF). In this model, the hub represents the centralized component responsible for monitoring and regulating both inbound and outbound traffic. Conversely, spokes represent isolated workloads where teams can execute their software or applications. These spokes are intricately linked to the hub. Typically, it falls upon the workload teams to create and manage the specific infrastructure they require.&lt;/p&gt;

&lt;p&gt;To ensure that workload teams adhere to compliance standards, the platform team equips them with essential building blocks for infrastructure creation. These building blocks are available to all teams needing infrastructure resources, including the platform team. Building blocks are often constructed using tools like Bicep or Terraform, both of which support the creation of modules that can be hosted in repositories such as Azure Container Registry or Terraform Cloud.&lt;/p&gt;

&lt;p&gt;Crucially, when the source code of these building blocks is accessible to all teams, any team member can contribute changes or updates. However, for quality control and to ensure ongoing compliance, all alterations to the building blocks require approval from the Platform team. This mechanism ensures that the building blocks continue to meet the necessary standards. In the context of InnerSource, the platform team serves as the trusted committer, overseeing these collaborative contributions.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Utilizing Packages&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In the contemporary landscape of software development, packages have become indispensable. Both frontend and backend applications heavily rely on these packages. Many of these packages are open-source and meticulously maintained by passionate individuals. They find their hosting platforms in package managers like NuGet and NPM, with GitHub as one of the most prominent platforms for hosting these open-source packages.&lt;/p&gt;

&lt;p&gt;GitHub’s foundation rests on principles of developer experience and open-source collaboration. This orientation means the source code for numerous packages is accessible to anyone, allowing for contributions from a wide community of developers. Changes to these packages undergo review and approval processes, typically overseen by package maintainers—dedicated groups of individuals who consistently contribute to the package’s development and upkeep.&lt;/p&gt;

&lt;p&gt;In addition to open-source packages, organizations also rely on company-specific packages. These packages often encompass specialized functionalities, such as authentication or logging methods. Rather than each team independently reinventing these functionalities, organizations follow a similar principle: creating packages that can be shared across multiple teams. These packages are available through platforms like Azure DevOps Artifacts or GitHub Packages.&lt;/p&gt;

&lt;p&gt;When multiple teams within an organization use these shared packages, it becomes essential that they have the flexibility to make adjustments and improvements as needed. Embracing the same open-source principles that govern external packages, these organizations naturally foster a community of regular contributors. Within this community, individuals emerge as trusted committers responsible for reviewing and approving changes to these vital shared packages, ensuring they remain robust and aligned with organizational needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Applications&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Like infrastructure and open-source packages, application developers can also adopt an open-source approach. Open-source applications often serve as alternatives to well-known applications, for example, Photoshop and The Gimp. Some companies even choose to open-source the tools they use, making them accessible to all. By doing so, they harness the collective power of the community to enhance these applications. The same principles that apply to open-source packages are extended to open-source applications, allowing anyone to contribute new features or fix bugs. Trusted committers play a pivotal role in reviewing and approving these changes.&lt;/p&gt;

&lt;p&gt;Now, imagine if these open-source principles, championed by passionate individuals, were applied to company software. Picture making the applications within a company available for everyone, enabling all employees to contribute to the company’s software.&lt;/p&gt;

&lt;p&gt;This approach fosters collaboration among teams and departments, effectively breaking down silos and encouraging knowledge sharing. It’s a recipe for innovative solutions as a broader set of eyes scrutinizes the codebase, potentially catching bugs, security vulnerabilities, or design flaws at an early stage. InnerSource encourages developers to share their expertise and best practices, elevating the overall skill level of your team and mitigating the risk of knowledge loss when employees depart.&lt;/p&gt;

&lt;p&gt;Distributing knowledge and responsibility makes the organization less susceptible to key-person dependencies. Others can readily step in to maintain and enhance the code if a developer leaves. Promoting InnerSource cultivates a culture of openness and transparency, resonating throughout the organization and enhancing company culture and employee morale.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Summary&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This article explores InnerSource, a practice that brings open-source principles to internal software development within organizations. InnerSource encourages collaboration and feedback while maintaining security boundaries. It operates on four key principles: Openness, Transparency, Prioritized Mentorship, and Voluntary Code Contribution. These principles address organizational challenges such as improving Developer Velocity and fostering collaboration.&lt;/p&gt;

&lt;p&gt;The benefits of InnerSource include reducing inter-team dependencies and resolving resource allocation challenges in larger organizations. It promotes collaboration, knowledge sharing, and efficiency. The article also outlines a role-based interaction model involving the Original Product Team, Product Owner, Trusted Committers, Contributors, and Consumers, all working together to develop and maintain projects.&lt;/p&gt;

&lt;p&gt;Embracing InnerSource helps you build an inclusive organization, where people are able to showcase their expertise and offers a modern approach to work that aligns with the preferences and values of younger generations. It promotes flexibility, cross-functional collaboration, knowledge sharing, and inclusivity, all of which can enhance job satisfaction, innovation, and organizational agility.&lt;/p&gt;

&lt;p&gt;(1): &lt;a href="https://www.mckinsey.com/capabilities/mckinsey-digital/our-insights/tech-forward/why-your-it-organization-should-prioritize-developer-experience"&gt;https://www.mckinsey.com/capabilities/mckinsey-digital/our-insights/tech-forward/why-your-it-organization-should-prioritize-developer-experience&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article is part of XPRT. Magazine #15&lt;br&gt;&lt;br&gt;
&lt;a href="https://xpirit.com/xprt-magazine-n-15/"&gt;Download here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VRGEAVGU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xpirit.com/wp-content/uploads/2023/10/Xebia_Xpirit_XPRT_15_mockup-3-600x400.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VRGEAVGU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://xpirit.com/wp-content/uploads/2023/10/Xebia_Xpirit_XPRT_15_mockup-3-600x400.png" alt="XPRT magazine 15" width="600" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://xpirit.com/innersource/"&gt;InnerSource&lt;/a&gt; appeared first on &lt;a href="https://xpirit.com"&gt;Xebia | Xpirit&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>innersource</category>
    </item>
    <item>
      <title>Accessing (private) GitHub resources from a Codespace</title>
      <dc:creator>Jesse Houwing</dc:creator>
      <pubDate>Mon, 02 Oct 2023 11:26:18 +0000</pubDate>
      <link>https://dev.to/xebia/accessing-private-github-resources-from-a-codespace-2ie4</link>
      <guid>https://dev.to/xebia/accessing-private-github-resources-from-a-codespace-2ie4</guid>
      <description>&lt;p&gt;&lt;a href="https://www.flickr.com/photos/tawheedmanzoor/2309847575" rel="noopener noreferrer"&gt;Photo by Tawheed Manzoor, used under Creative Commons&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By default, your GitHub Codespace carries an authorization token for the repository the codespace was opened in as well as all public repositories your user has access to.&lt;/p&gt;

&lt;p&gt;You can request access to other repositories in the same account or organization through the &lt;code&gt;devcontainer.json&lt;/code&gt; 's &lt;code&gt;customizations&lt;/code&gt; section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"customizations": {
    // Configure properties specific to Codespaces.
    "codespaces": {
        "repositories": {
            // List additional repositories you'll need access to:
            "jessehouwing/demo": {
                "permissions": {
                    "contents": "read",
                    "packages": "read"
                }
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to access packages or repositories from another organization though, you're out of luck. Even though you can request access to repositories outside of your organization or account, GitHub won't grant you that access when the Codespace starts:&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%2Fthfjb7nvk75p7qlhs1va.png" 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%2Fthfjb7nvk75p7qlhs1va.png" alt="Accessing (private) GitHub resources from a Codespace" width="569" height="393"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;"The following permissions were also requested, but are not available"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If this happens, and you do need access to other private repositories (or in my case public repositories that require SAML authentication of your identity), you'll need to do a little dance inside your codespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@jessehouwing ➜ /workspaces/jessehouwing (master) $ unset GITHUB_TOKEN
@jessehouwing ➜ /workspaces/jessehouwing (master) $ unset GH_TOKEN
@jessehouwing ➜ /workspaces/jessehouwing (master) $ docker logout grcr.io
Removing login credentials for grcr.io
@jessehouwing ➜ /workspaces/jessehouwing (master) $ gh auth login
? What account do you want to log into? GitHub.com
? What is your preferred protocol for Git operations? HTTPS
? Authenticate Git with your GitHub credentials? Yes
? How would you like to authenticate GitHub CLI? Login with a web browser

! First copy your one-time code: XXX-XXX
Press Enter to open github.com in your browser... 
✓ Authentication complete.
- gh config set -h github.com git_protocol https
✓ Configured git protocol
✓ Logged in as jessehouwing
@jessehouwing ➜ /workspaces/jessehouwing (master) $ gh extension install github/gh-actions-importer
✓ Installed extension github/gh-actions-importer
@jessehouwing ➜ /workspaces/jessehouwing (master) $ gh actions-importer update
Updating ghcr.io/actions-importer/cli:latest...
ghcr.io/actions-importer/cli:latest up-to-date
@jessehouwing ➜ /workspaces/jessehouwing (master) $ 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dance goes as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First we unset the environment variables that hold the access tokens of the Codespace. &lt;/li&gt;
&lt;li&gt;Then we ensure we're logged out of the GitHub container registry. &lt;/li&gt;
&lt;li&gt;Then we reauthenticate to github using the github CLI&lt;/li&gt;
&lt;/ol&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%2F3pzbdtutv961vdc3vojp.png" 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%2F3pzbdtutv961vdc3vojp.png" alt="Accessing (private) GitHub resources from a Codespace" width="546" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Outside of the codespace we perform the login and SAML authorization:&lt;/li&gt;
&lt;/ol&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%2Fj5psyg0cxgy9ajkds0dx.png" 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%2Fj5psyg0cxgy9ajkds0dx.png" alt="Accessing (private) GitHub resources from a Codespace" width="512" height="768"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Then we can access the protected repositories.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Like I mentioned before, this dance is only needed if you require access to protected resources &lt;strong&gt;outside&lt;/strong&gt; of the account or organization that hosts the GitHub Codespace.&lt;/p&gt;

&lt;p&gt;I personally encounter this mostly because I'm a member of the GitHub organization and thus I need to authorize my tokens to access any repository hosted by the GitHub org.&lt;/p&gt;

&lt;p&gt;You may be encountering this issue because your employer has more than one organization on GitHub and you need to access resources from one organization from a Codespace that's hosted by another.&lt;/p&gt;

</description>
      <category>github</category>
      <category>githubcodespaces</category>
      <category>codespaces</category>
    </item>
    <item>
      <title>Investigating az-cli performance on the hosted Azure Pipelines and GitHub Runners</title>
      <dc:creator>Jesse Houwing</dc:creator>
      <pubDate>Thu, 28 Sep 2023 21:18:03 +0000</pubDate>
      <link>https://dev.to/xebia/investigating-az-cli-performance-on-the-hosted-azure-pipelines-and-github-runners-4ogg</link>
      <guid>https://dev.to/xebia/investigating-az-cli-performance-on-the-hosted-azure-pipelines-and-github-runners-4ogg</guid>
      <description>&lt;p&gt;I've been building a few more workflows and pipelines over the past few days and had been experimenting with the az-cli. And I've been running into all kinds of performance issues.&lt;/p&gt;

&lt;p&gt;Azure CLI is a great nifty tool to chat to Azure as well as Azure DevOps and there's a &lt;code&gt;AzureCLI@v2&lt;/code&gt; task in Azure DevOps that preconfigures your Azure subscription and all.&lt;/p&gt;

&lt;p&gt;While testing I got increasingly frustrated by how slow &lt;code&gt;az&lt;/code&gt; is on GitHub Actions and Azure Pipelines hosted runners. But only on Windows. So, I've been digging into &lt;em&gt;why&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Over the past week I've found quite a few issues, files a few issues and submitted a couple of pull requests. I'll walk you through my findings, they may help improve the performance of your workflows too!&lt;/p&gt;

&lt;h2&gt;
  
  
  Case matters
&lt;/h2&gt;

&lt;p&gt;It turns out that the casing of your commands matters when it comes to &lt;code&gt;az&lt;/code&gt;. You wouldn't expect it, &lt;code&gt;az version&lt;/code&gt; will take about 12 seconds to run on the hosted runner including the overhead of starting a fresh powershell session.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;az Version&lt;/code&gt; will take about &lt;strong&gt;one minute&lt;/strong&gt;. Why? Well, it turns out that &lt;code&gt;az&lt;/code&gt; caches all the commands that are available from its many plugins, and that it looks up the command by key to see if it recognises what you've passed in. It performs that lookup case sensitive.&lt;/p&gt;

&lt;p&gt;Issue filed:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/Azure/azure-cli/issues/27497" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        command index lookup is case sensitive
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#27497&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F4173387%3Fv%3D4" alt="jessehouwing avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;jessehouwing&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/Azure/azure-cli/issues/27497" rel="noopener noreferrer"&gt;&lt;time&gt;Sep 28, 2023&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;h3 id="user-content-describe-the-bug"&gt;Describe the bug&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;When you run&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;az vErSiOn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;a command index rebuild is triggered.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;az version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;does not trigger a command index rebuild&lt;/p&gt;
&lt;h3 id="user-content-related-command"&gt;Related command&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;any command&lt;/p&gt;
&lt;h3 id="user-content-errors"&gt;Errors&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;cli.azure.cli.core: No module found from index for '['VeRSIoN', '--debug']'
cli.azure.cli.core: Loading all modules and extensions
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="user-content-issue-script--debug-output"&gt;Issue script &amp;amp; Debug output&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;Command&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;C:\Users\JesseHouwing&amp;gt;az VeRSIoN --debug
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cli.knack.cli: Command arguments: ['VeRSIoN', '--debug']
cli.knack.cli: __init__ debug log:
Enable color in terminal.
Enable VT mode.
cli.knack.cli: Event: Cli.PreExecute []
cli.knack.cli: Event: CommandParser.OnGlobalArgumentsCreate [&amp;lt;function CLILogging.on_global_arguments at 0x01C3A4F0&amp;gt;, &amp;lt;function OutputProducer.on_global_arguments at 0x01E3B730&amp;gt;, &amp;lt;function CLIQuery.on_global_arguments at 0x01E58388&amp;gt;]
cli.knack.cli: Event: CommandInvoker.OnPreCommandTableCreate []
cli.azure.cli.core: No module found from index for '['VeRSIoN', '--debug']'
cli.azure.cli.core: Loading all modules and extensions
cli.azure.cli.core: Discovered command modules: ['acr', 'acs', 'advisor', 'ams', 'apim', 'appconfig', 'appservice', 'aro', 'backup', 'batch', 'batchai', 'billing', 'botservice', 'cdn', 'cloud', 'cognitiveservices', 'config', 'configure', 'consumption', 'container', 'containerapp', 'cosmosdb', 'databoxedge', 'dla', 'dls', 'dms', 'eventgrid', 'eventhubs', 'extension', 'feedback', 'find', 'hdinsight', 'identity', 'interactive', 'iot', 'keyvault', 'kusto', 'lab', 'managedservices', 'maps', 'marketplaceordering', 'monitor', 'mysql', 'netappfiles', 'network', 'policyinsights', 'privatedns', 'profile', 'rdbms', 'redis', 'relay', 'resource', 'role', 'search', 'security', 'servicebus', 'serviceconnector', 'servicefabric', 'signalr', 'sql', 'sqlvm', 'storage', 'synapse', 'util', 'vm']
cli.azure.cli.core: Loading command modules:
cli.azure.cli.core: Name                  Load Time    Groups  Commands
cli.azure.cli.core: acr                       0.142        34       144
cli.azure.cli.core: acs                       0.027         7        54
cli.azure.cli.core: advisor                   0.003         3         6
cli.azure.cli.core: ams                       0.019        22       100
cli.azure.cli.core: apim                      0.008        14        68
cli.azure.cli.core: appconfig                 0.004         9        47
cli.azure.cli.core: appservice                0.079        73       260
cli.azure.cli.core: aro                       0.014         1        10
cli.azure.cli.core: backup                    0.004        16        59
cli.azure.cli.core: batch                     0.032        34       102
cli.azure.cli.core: batchai                   0.004        10        30
cli.azure.cli.core: billing                   0.009        19        52
cli.azure.cli.core: botservice                0.004        12        42
cli.azure.cli.core: cdn                       0.006        39       133
cli.azure.cli.core: cloud                     0.002         1         7
cli.azure.cli.core: cognitiveservices         0.003        10        33
cli.azure.cli.core: config                    0.003         2         7
cli.azure.cli.core: configure                 0.002         2         5
cli.azure.cli.core: consumption               0.026         8         9
cli.azure.cli.core: container                 0.014         1        11
cli.azure.cli.core: containerapp              0.130        36       115
cli.azure.cli.core: cosmosdb                  0.016        58       192
cli.azure.cli.core: databoxedge               0.007         5        27
cli.azure.cli.core: dla                       0.004        23        62
cli.azure.cli.core: dls                       0.004         7        41
cli.azure.cli.core: dms                       0.003         3        22
cli.azure.cli.core: eventgrid                 0.005        25        96
cli.azure.cli.core: eventhubs                 0.018        13        20
cli.azure.cli.core: extension                 0.002         1         7
cli.azure.cli.core: feedback                  0.002         1         2
cli.azure.cli.core: find                      0.002         1         1
cli.azure.cli.core: hdinsight                 0.009         8        39
cli.azure.cli.core: identity                  0.004         2        11
cli.azure.cli.core: interactive               0.001         1         1
cli.azure.cli.core: iot                       0.096        19        82
cli.azure.cli.core: keyvault                  0.009        22       133
cli.azure.cli.core: kusto                     0.004         3        14
cli.azure.cli.core: lab                       0.004        11        34
cli.azure.cli.core: managedservices           0.003         3         8
cli.azure.cli.core: maps                      0.002         5        13
cli.azure.cli.core: marketplaceordering       0.006         1         2
cli.azure.cli.core: monitor                   0.307        21        67
cli.azure.cli.core: mysql                     0.104        14        49
cli.azure.cli.core: netappfiles               0.006        17        96
cli.azure.cli.core: network                   0.130       103       337
cli.azure.cli.core: policyinsights            0.016         9        17
cli.azure.cli.core: privatedns                0.023        14        60
cli.azure.cli.core: profile                   0.002         2         8
cli.azure.cli.core: rdbms                     0.024        44       185
cli.azure.cli.core: redis                     0.003         5        27
cli.azure.cli.core: relay                     0.034         7         8
cli.azure.cli.core: resource                  0.015        51       227
cli.azure.cli.core: role                      0.003        17        61
cli.azure.cli.core: search                    0.003         7        22
cli.azure.cli.core: security                  0.006        48       104
cli.azure.cli.core: servicebus                0.019        12        17
cli.azure.cli.core: serviceconnector          0.054        16       235
cli.azure.cli.core: servicefabric             0.018        27        76
cli.azure.cli.core: signalr                   0.003         8        30
cli.azure.cli.core: sql                       0.017        56       215
cli.azure.cli.core: sqlvm                     0.024         4        20
cli.azure.cli.core: storage                   0.039        58       272
cli.azure.cli.core: synapse                   0.015        54       246
cli.azure.cli.core: util                      0.002         3         7
cli.azure.cli.core: vm                        0.049        57       265
cli.azure.cli.core: Total (65)                1.653      1219      4752
cli.azure.cli.core: Loading extensions:
cli.azure.cli.core: Name                  Load Time    Groups  Commands  Directory
cli.azure.cli.core: azure-devops              0.150        60       192  C:\Users\JesseHouwing\.azure\cliextensions\azure-devops
cli.azure.cli.core: containerapp              0.015        31        95  C:\Users\JesseHouwing\.azure\cliextensions\containerapp
cli.azure.cli.core: init                      0.003         1         1  C:\Users\JesseHouwing\.azure\cliextensions\init
cli.azure.cli.core: Total (3)                 0.169        92       288
cli.azure.cli.core: Loaded 1266 groups, 4947 commands.
cli.azure.cli.core: Updated command index in 0.005 seconds.
cli.knack.cli: Event: CommandInvoker.OnPreCommandTableTruncate [&amp;lt;function AzCliLogging.init_command_file_logging at 0x040095C8&amp;gt;]
cli.azure.cli.core.azlogging: metadata file logging enabled - writing logs to 'C:\Users\JesseHouwing\.azure\commands\2023-09-28.20-42-39.VeRSIoN.11404.log'.
az_command_data_logger: command args: version --debug
cli.knack.cli: Event: CommandInvoker.OnPreArgumentLoad [&amp;lt;function register_global_subscription_argument.&amp;lt;locals&amp;gt;.add_subscription_parameter at 0x04036730&amp;gt;]
cli.knack.cli: Event: CommandInvoker.OnPostArgumentLoad []
cli.knack.cli: Event: CommandInvoker.OnPostCommandTableCreate [&amp;lt;function register_ids_argument.&amp;lt;locals&amp;gt;.add_ids_arguments at 0x040446A0&amp;gt;, &amp;lt;function register_cache_arguments.&amp;lt;locals&amp;gt;.add_cache_arguments at 0x04044898&amp;gt;]
cli.knack.cli: Event: CommandInvoker.OnCommandTableLoaded []
cli.knack.cli: Event: CommandInvoker.OnPreParseArgs [&amp;lt;function _documentdb_deprecate at 0x05179F58&amp;gt;]
cli.knack.cli: Event: CommandInvoker.OnPostParseArgs [&amp;lt;function OutputProducer.handle_output_argument at 0x01E3B778&amp;gt;, &amp;lt;function CLIQuery.handle_query_parameter at 0x01E583D0&amp;gt;, &amp;lt;function register_ids_argument.&amp;lt;locals&amp;gt;.parse_ids_arguments at 0x04044850&amp;gt;, &amp;lt;function handler at 0x052DA4F0&amp;gt;, &amp;lt;function DevCommandsLoader.post_parse_args at 0x07439D60&amp;gt;]
cli.knack.cli: Event: CommandInvoker.OnTransformResult [&amp;lt;function _resource_group_transform at 0x04032DF0&amp;gt;, &amp;lt;function _x509_from_base64_to_hex_transform at 0x04032E38&amp;gt;]
cli.knack.cli: Event: CommandInvoker.OnFilterResult []
{
  "azure-cli": "2.53.0",
  "azure-cli-core": "2.53.0",
  "azure-cli-telemetry": "1.1.0",
  "extensions": {
    "azure-devops": "0.26.0",
    "containerapp": "0.3.29",
    "init": "0.1.0"
  }
}
cli.knack.cli: Event: Cli.SuccessfulExecute []
cli.knack.cli: Event: Cli.PostExecute [&amp;lt;function AzCliLogging.deinit_cmd_metadata_logging at 0x040096E8&amp;gt;]
az_command_data_logger: exit code: 0
cli.__main__: Command ran in 2.197 seconds (init: 0.315, invoke: 1.882)
telemetry.main: Begin splitting cli events and extra events, total events: 1
telemetry.client: Accumulated 0 events. Flush the clients.
telemetry.main: Finish splitting cli events and extra events, cli events: 1
telemetry.save: Save telemetry record of length 3292 in cache
telemetry.main: Begin creating telemetry upload process.
telemetry.process: Creating upload process: "C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\python.exe C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\Lib\site-packages\azure\cli\telemetry\__init__.pyc C:\Users\JesseHouwing\.azure"
telemetry.process: Return from creating process
telemetry.main: Finish creating telemetry upload process.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="user-content-expected-behavior"&gt;Expected behavior&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;The command is compared to the index case insensitive and the command index is &lt;strong&gt;not&lt;/strong&gt; invalidated.&lt;/p&gt;
&lt;h3 id="user-content-environment-summary"&gt;Environment Summary&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;C:\Users\JesseHouwing&amp;gt;az version
{
"azure-cli": "2.53.0",
"azure-cli-core": "2.53.0",
"azure-cli-telemetry": "1.1.0",
"extensions": {
"azure-devops": "0.26.0",
"containerapp": "0.3.29",
"init": "0.1.0"
}
}&lt;/p&gt;
&lt;h3 id="user-content-additional-context"&gt;Additional context&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;No response&lt;/em&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Azure/azure-cli/issues/27497" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;For now, make sure you call &lt;code&gt;az devops&lt;/code&gt; and not &lt;code&gt;az DevOps&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Darn you autocorrect for correcting devops to DevOps all the time!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;az devops login&lt;/code&gt; vs &lt;code&gt;AZURE_DEVOPS_EXT_PAT&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;To authenticate to Azure DevOps, you have a few options to chose from. You can use &lt;code&gt;AzureCLI@2&lt;/code&gt; with an Azure service connection or add &lt;code&gt;az devops login&lt;/code&gt; to your script or pass a token through the &lt;code&gt;AZURE_DEVOPS_EXT_PAT&lt;/code&gt; environment variable.&lt;/p&gt;

&lt;p&gt;Configuring your Azure Service Connection is the slowest of the bunch. Followed by &lt;code&gt;az devops login&lt;/code&gt; where as the environment variable should be the fastest of the bunch.&lt;/p&gt;

&lt;p&gt;But it turns out to be much more complex. That's because &lt;code&gt;az devops login&lt;/code&gt; will try to install python's &lt;code&gt;keyring&lt;/code&gt;package the first time it runs, and on the Hosted runners, the command has never been called before, thus &lt;em&gt;adding 10-20s&lt;/em&gt; to the first call.&lt;/p&gt;

&lt;p&gt;Collaborated on a pull request to force &lt;code&gt;keyring&lt;/code&gt; installation during image creation:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/actions/runner-images/pull/8410" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        [windows] warmup "az devops" for the first run
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#8410&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/ilia-shipitsin" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F125650415%3Fv%3D4" alt="ilia-shipitsin avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/ilia-shipitsin" rel="noopener noreferrer"&gt;ilia-shipitsin&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/actions/runner-images/pull/8410" rel="noopener noreferrer"&gt;&lt;time&gt;Sep 28, 2023&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;as Jesse Houwing has found "az devops" warms up during first run which takes ~40 sec.&lt;/p&gt;
&lt;p&gt;warm up is done by running "az devops  --help" with config redirected to persistent "C:" location, also keyring installation requires "fake" login&lt;/p&gt;
&lt;p&gt;original PR: &lt;a href="https://github.com/actions/runner-images/pull/8294" rel="noopener noreferrer"&gt;https://github.com/actions/runner-images/pull/8294&lt;/a&gt;&lt;/p&gt;
&lt;h1 id="user-content-description"&gt;Description&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h1&gt;
&lt;p&gt;warming up "az devops" first invocation.
due to security reasons we cannot accept original PR: &lt;a href="https://github.com/actions/runner-images/pull/8294" rel="noopener noreferrer"&gt;https://github.com/actions/runner-images/pull/8294&lt;/a&gt;&lt;/p&gt;
&lt;h4 id="user-content-related-issue"&gt;Related issue:&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://github.com/actions/runner-images/issues/8296" rel="noopener noreferrer"&gt;https://github.com/actions/runner-images/issues/8296&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="user-content-check-list"&gt;Check list&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[x] Related issue / work item is attached&lt;/li&gt;
&lt;li&gt;[ ] Tests are written (if applicable)&lt;/li&gt;
&lt;li&gt;[ ] Documentation is updated (if applicable)&lt;/li&gt;
&lt;li&gt;[ ] Changes are tested and related VM images are successfully generated&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/actions/runner-images/pull/8410" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;And filed an issue to make sure this package is included in &lt;code&gt;az devops&lt;/code&gt; by default:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/Azure/azure-devops-cli-extension/issues/1367" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        [Feature Request] Install keyring by default or offer a way to install keyring without causing error messages
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#1367&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F4173387%3Fv%3D4" alt="jessehouwing avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;jessehouwing&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/Azure/azure-devops-cli-extension/issues/1367" rel="noopener noreferrer"&gt;&lt;time&gt;Sep 28, 2023&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;&lt;strong&gt;Is your feature request related to a problem? Please describe.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When calling &lt;code&gt;az devops login&lt;/code&gt; for the very first time, it installs pythons keyring package. For some reason that's not included in the default setup. This adds needless time to a first invocation of &lt;code&gt;az devops login&lt;/code&gt; on the GitHub Hosted Runners and Azure Pipelines.&lt;/p&gt;
&lt;p&gt;You can force the installation of keyring using&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo "dummy" | az devops login
az devops logout
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On the GitHub/Azure Pipelines hosted runner the provisioning of the image happens on a non-interactive session and &lt;code&gt;az devops login&lt;/code&gt; fails with an error along those lines.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ERROR: (1312, 'CredRead', 'A specified logon session does not exist. It may already have been terminated')
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunatly, &lt;code&gt;az devops&lt;/code&gt; doesn't provide a clean way to install keyring during installation or through a command other than catching the failed login.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Describe the solution you'd like&lt;/strong&gt;
Either azdevops should preinstall keyring during normal installation of the extension. It's unclear why it's not included in the first place.&lt;/p&gt;
&lt;p&gt;Or there should be a clean way to run &lt;code&gt;az devops install-dependencies&lt;/code&gt; or something to have it download its dependencies in a provisioning scenario.&lt;/p&gt;
&lt;p&gt;I grabbed the following lines from the code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$pythonPath = resolve-path (join-path ([System.IO.Path]::GetDirectoryName((Get-Command az).Path)) "..\python.exe")
Invoke-ValidateCommand -Command "&amp;amp; '$pythonPath' -m pip install keyring~=17.1.1 --target '$env:AZURE_EXTENSION_DIR\azure-devops' -vv --disable-pip-version-check --no-cache-dir"  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and it works. But since there is no way to grab the correct version of keyring from anywhere other than the sourcecode of az devops, it's a very brittle contract.&lt;/p&gt;
&lt;p&gt;For now we're looking into just swallowing any message printed by &lt;code&gt;az devops login&lt;/code&gt;. But that's of course also a brittle contract.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cli.azext_devops.dev.common.pip_helper: installing keyring~=17.1.1
cli.azure.cli.core.extension.operations: Running: ['C:\\Program Files\\Microsoft SDKs\\Azure\\CLI2\\python.exe', '-m', 'pip', 'install', 'keyring~=17.1.1', '--target', 'C:\\Users\\WDAGUtilityAccount\\.azure\\cliextensions\\azure-devops', '-vv', '--disable-pip-version-check', '--no-cache-dir']
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Additional context&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I know I could also set an environment variable with an access token instead of calling &lt;code&gt;az devops login&lt;/code&gt;, unfortunately that also adds a 10 second delay on the GitHub Hosted Runner / Azure Pipelines runner as it tries to run &lt;code&gt;az login&lt;/code&gt;, sees it fail and only then reverts to using the token supplied on the commandline.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Azure/azure-devops-cli-extension/issues/1367" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;So you might think that setting &lt;code&gt;AZURE_DEVOPS_EXT_PAT&lt;/code&gt; will be the fastest, but what happens under the hood might be surprising: &lt;code&gt;az devops&lt;/code&gt; will first try to run &lt;code&gt;az login&lt;/code&gt; and &lt;code&gt;az devops login&lt;/code&gt; &lt;strong&gt;before&lt;/strong&gt; attempting to use the environment variable, even if you explicitly pass it in. There should be a way to force the configuration used.&lt;/p&gt;

&lt;p&gt;Filed an issue:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/Azure/azure-cli/issues/27439" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        az cli seems to spend 10 seconds looking for account config, even if it doesn't need them
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#27439&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F4173387%3Fv%3D4" alt="jessehouwing avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;jessehouwing&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/Azure/azure-cli/issues/27439" rel="noopener noreferrer"&gt;&lt;time&gt;Sep 20, 2023&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;h3 id="user-content-describe-the-bug"&gt;Describe the bug&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;While looking into what causes the az-cli to load slowly on the hosted agents of GitHub Actions and Azure pipelines I noticed that az tries to look for accounts and throws a couple of exceptions even if the account isn't needed.&lt;/p&gt;
&lt;p&gt;In this case the access token to access Azure DevOps is supplied through the environment, yet az is trying to load accounts and spends unneeded time there.&lt;/p&gt;
&lt;p&gt;It's hard to tell from the logs, bet between the last logged line and the error handling there is a jump of about 10 seconds in the Azure pipelines log. Would be lovely if that time waste could be prevented.&lt;/p&gt;
&lt;h3 id="user-content-related-command"&gt;Related command&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;Az DevOps pipelines show ...&lt;/p&gt;
&lt;h3 id="user-content-errors"&gt;Errors&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;2023-09-15T18:37:12.7002991Z DEBUG: cli.knack.cli: Event: CommandInvoker.OnPreCommandTableTruncate [&amp;lt;function AzCliLogging.init_command_file_logging at 0x0000025BD8AEC430&amp;gt;]
2023-09-15T18:37:12.7003914Z DEBUG: cli.knack.cli: Event: CommandInvoker.OnPreArgumentLoad [&amp;lt;function register_global_subscription_argument..add_subscription_parameter at 0x0000025BD8AEF0A0&amp;gt;]
2023-09-15T18:37:22.0011676Z DEBUG: cli.knack.cli: Event: CommandInvoker.OnPostArgumentLoad []
2023-09-15T18:37:22.0012102Z DEBUG: cli.knack.cli: Event: CommandInvoker.OnPostCommandTableCreate [&amp;lt;function register_ids_argument..add_ids_arguments at 0x0000025BD8B51090&amp;gt;, &amp;lt;function register_cache_arguments..add_cache_arguments at 0x0000025BD8B511B0&amp;gt;]
2023-09-15T18:37:22.0026227Z DEBUG: cli.knack.cli: Event: CommandInvoker.OnCommandTableLoaded []
2023-09-15T18:37:22.0026678Z DEBUG: cli.knack.cli: Event: CommandInvoker.OnPreParseArgs []
2023-09-15T18:37:22.3327775Z DEBUG: cli.knack.cli: Event: CommandInvoker.OnPostParseArgs [&amp;lt;function OutputProducer.handle_output_argument at 0x0000025BD63AFF40&amp;gt;, &amp;lt;function CLIQuery.handle_query_parameter at 0x0000025BD63F92D0&amp;gt;, &amp;lt;function register_ids_argument..parse_ids_arguments at 0x0000025BD8B51120&amp;gt;, &amp;lt;function DevCommandsLoader.post_parse_args at 0x0000025BD8B72B90&amp;gt;]
2023-09-15T18:37:22.3348603Z DEBUG: cli.azext_devops.dev.common.services: PAT is present which can be used against this instance
2023-09-15T18:37:22.3375557Z DEBUG: cli.azure.cli.core: Current cloud config:
2023-09-15T18:37:22.3375819Z AzureCloud
2023-09-15T18:37:22.3376906Z DEBUG: cli.azext_devops.dev.common.services: az login is not present
2023-09-15T18:37:22.3382543Z DEBUG: cli.azext_devops.dev.common.services: There are no active accounts.
2023-09-15T18:37:22.3382797Z Traceback (most recent call last):
2023-09-15T18:37:22.3383541Z   File "D:\a_work\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\azure/cli/core/_profile.py", line 537, in get_current_account_user
2023-09-15T18:37:22.3384147Z   File "D:\a_work\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\azure/cli/core/_profile.py", line 546, in get_subscription
2023-09-15T18:37:22.3384535Z knack.util.CLIError: Please run 'az login' to setup account.
2023-09-15T18:37:22.3384768Z
2023-09-15T18:37:22.3385009Z During handling of the above exception, another exception occurred:
2023-09-15T18:37:22.3385200Z
2023-09-15T18:37:22.3385466Z Traceback (most recent call last):
2023-09-15T18:37:22.3385884Z   File "C:\Program Files\Common Files\AzureCliExtensionDirectory\azure-devops\azext_devops\dev\common\services.py", line 61, in _get_credentials
2023-09-15T18:37:22.3386261Z     token_from_az_login = get_token_from_az_logins(organization, pat_token_present)
2023-09-15T18:37:22.3386725Z   File "C:\Program Files\Common Files\AzureCliExtensionDirectory\azure-devops\azext_devops\dev\common\services.py", line 118, in get_token_from_az_logins
2023-09-15T18:37:22.3387095Z     dummy_user = profile.get_current_account_user()     # noqa: F841
2023-09-15T18:37:22.3387524Z   File "D:\a_work\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\azure/cli/core/_profile.py", line 539, in get_current_account_user
2023-09-15T18:37:22.3387878Z knack.util.CLIError: There are no active accounts.
2023-09-15T18:37:22.3388195Z INFO: cli.azext_devops.dev.common.services: received PAT from environment variable
2023-09-15T18:37:22.3388587Z INFO: cli.azext_devops.dev.common.services: Creating connection with personal access token.&lt;/p&gt;
&lt;h3 id="user-content-issue-script--debug-output"&gt;Issue script &amp;amp; Debug output&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;2023-09-15T18:37:12.7002991Z DEBUG: cli.knack.cli: Event: CommandInvoker.OnPreCommandTableTruncate [&amp;lt;function AzCliLogging.init_command_file_logging at 0x0000025BD8AEC430&amp;gt;]
2023-09-15T18:37:12.7003914Z DEBUG: cli.knack.cli: Event: CommandInvoker.OnPreArgumentLoad [&amp;lt;function register_global_subscription_argument..add_subscription_parameter at 0x0000025BD8AEF0A0&amp;gt;]
2023-09-15T18:37:22.0011676Z DEBUG: cli.knack.cli: Event: CommandInvoker.OnPostArgumentLoad []
2023-09-15T18:37:22.0012102Z DEBUG: cli.knack.cli: Event: CommandInvoker.OnPostCommandTableCreate [&amp;lt;function register_ids_argument..add_ids_arguments at 0x0000025BD8B51090&amp;gt;, &amp;lt;function register_cache_arguments..add_cache_arguments at 0x0000025BD8B511B0&amp;gt;]
2023-09-15T18:37:22.0026227Z DEBUG: cli.knack.cli: Event: CommandInvoker.OnCommandTableLoaded []
2023-09-15T18:37:22.0026678Z DEBUG: cli.knack.cli: Event: CommandInvoker.OnPreParseArgs []
2023-09-15T18:37:22.3327775Z DEBUG: cli.knack.cli: Event: CommandInvoker.OnPostParseArgs [&amp;lt;function OutputProducer.handle_output_argument at 0x0000025BD63AFF40&amp;gt;, &amp;lt;function CLIQuery.handle_query_parameter at 0x0000025BD63F92D0&amp;gt;, &amp;lt;function register_ids_argument..parse_ids_arguments at 0x0000025BD8B51120&amp;gt;, &amp;lt;function DevCommandsLoader.post_parse_args at 0x0000025BD8B72B90&amp;gt;]
2023-09-15T18:37:22.3348603Z DEBUG: cli.azext_devops.dev.common.services: PAT is present which can be used against this instance
2023-09-15T18:37:22.3375557Z DEBUG: cli.azure.cli.core: Current cloud config:
2023-09-15T18:37:22.3375819Z AzureCloud
2023-09-15T18:37:22.3376906Z DEBUG: cli.azext_devops.dev.common.services: az login is not present
2023-09-15T18:37:22.3382543Z DEBUG: cli.azext_devops.dev.common.services: There are no active accounts.
2023-09-15T18:37:22.3382797Z Traceback (most recent call last):
2023-09-15T18:37:22.3383541Z   File "D:\a_work\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\azure/cli/core/_profile.py", line 537, in get_current_account_user
2023-09-15T18:37:22.3384147Z   File "D:\a_work\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\azure/cli/core/_profile.py", line 546, in get_subscription
2023-09-15T18:37:22.3384535Z knack.util.CLIError: Please run 'az login' to setup account.
2023-09-15T18:37:22.3384768Z
2023-09-15T18:37:22.3385009Z During handling of the above exception, another exception occurred:
2023-09-15T18:37:22.3385200Z
2023-09-15T18:37:22.3385466Z Traceback (most recent call last):
2023-09-15T18:37:22.3385884Z   File "C:\Program Files\Common Files\AzureCliExtensionDirectory\azure-devops\azext_devops\dev\common\services.py", line 61, in _get_credentials
2023-09-15T18:37:22.3386261Z     token_from_az_login = get_token_from_az_logins(organization, pat_token_present)
2023-09-15T18:37:22.3386725Z   File "C:\Program Files\Common Files\AzureCliExtensionDirectory\azure-devops\azext_devops\dev\common\services.py", line 118, in get_token_from_az_logins
2023-09-15T18:37:22.3387095Z     dummy_user = profile.get_current_account_user()     # noqa: F841
2023-09-15T18:37:22.3387524Z   File "D:\a_work\1\s\build_scripts\windows\artifacts\cli\Lib\site-packages\azure/cli/core/_profile.py", line 539, in get_current_account_user
2023-09-15T18:37:22.3387878Z knack.util.CLIError: There are no active accounts.
2023-09-15T18:37:22.3388195Z INFO: cli.azext_devops.dev.common.services: received PAT from environment variable
2023-09-15T18:37:22.3388587Z INFO: cli.azext_devops.dev.common.services: Creating connection with personal access token.&lt;/p&gt;
&lt;h3 id="user-content-expected-behavior"&gt;Expected behavior&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;Account info is only loaded when needed. Lack of account data doesn't result in a swallowed error.&lt;/p&gt;
&lt;h3 id="user-content-environment-summary"&gt;Environment Summary&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;azure-cli 2.52.0&lt;/p&gt;
&lt;p&gt;core 2.52.0
telemetry 1.1.0&lt;/p&gt;
&lt;p&gt;Extensions:
azure-devops 0.26.0&lt;/p&gt;
&lt;p&gt;Dependencies:
msal 1.24.0b1
azure-mgmt-resource 23.1.0b2&lt;/p&gt;
&lt;p&gt;Python location 'C:\Program Files\Microsoft SDKs\Azure\CLI2\python.exe'
Extensions directory 'C:\Program Files\Common Files\AzureCliExtensionDirectory'&lt;/p&gt;
&lt;p&gt;Python (Windows) 3.10.10 (tags/v3.10.10:aad5f6a, Feb 7 2023, 17:20:36) [MSC v.1929 64 bit (AMD64)]&lt;/p&gt;
&lt;h3 id="user-content-additional-context"&gt;Additional context&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/actions/runner-images/pull/8294" rel="noopener noreferrer"&gt;https://github.com/actions/runner-images/pull/8294&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Azure/azure-cli/issues/27439" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  First run of az on the hosted runner &lt;em&gt;always&lt;/em&gt; causes a rebuild of the command index
&lt;/h2&gt;

&lt;p&gt;Similar to the case matters issue above, the first time &lt;code&gt;az&lt;/code&gt; is invoked on the hosted runners a command index rebuild is triggered. Why? Because the command index doesn't exist in the user profile of the user that runs your workflow. These files are normally stored in your profile directory under &lt;code&gt;~/.azure&lt;/code&gt; and &lt;code&gt;~/.azure-devops&lt;/code&gt;, but since your workflow runs in a pristine user profile, these cached files are gone.&lt;/p&gt;

&lt;p&gt;Submitted a pull request to move these folders to a persistent location:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/actions/runner-images/pull/8294" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Runs az and az-devops during warmup
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#8294&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F4173387%3Fv%3D4" alt="jessehouwing avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;jessehouwing&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/actions/runner-images/pull/8294" rel="noopener noreferrer"&gt;&lt;time&gt;Sep 14, 2023&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;h1 id="user-content-description"&gt;Description&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h1&gt;
&lt;p&gt;Speed up performance of &lt;code&gt;az&lt;/code&gt; and &lt;code&gt;az devops&lt;/code&gt;. In my own experiments savings are sometimes more than 60 seconds.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;This is done by changing the default settings of &lt;code&gt;az&lt;/code&gt; based on the recommended settings from &lt;code&gt;az init&lt;/code&gt; for automation workflows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enables the settings recommended by &lt;code&gt;az init&lt;/code&gt; for automation workflows.&lt;/li&gt;
&lt;li&gt;Disables auto-upgrade&lt;/li&gt;
&lt;li&gt;Disables colors&lt;/li&gt;
&lt;li&gt;Disables surveys&lt;/li&gt;
&lt;li&gt;Disables progress bars&lt;/li&gt;
&lt;li&gt;Disables recommendations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It invokes &lt;code&gt;az&lt;/code&gt; and &lt;code&gt;az devops&lt;/code&gt; during the image build to ensure Python pre-caches its objects.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It moves the &lt;code&gt;.azure&lt;/code&gt; and &lt;code&gt;.azure-devops&lt;/code&gt; and &lt;code&gt;.azure-devops/cache&lt;/code&gt; folders into the CommonFiles directory similarly to how the runner already moved installed extensions to the CommonFiles directory.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First call performance, especially of &lt;code&gt;az devops&lt;/code&gt; commands will still be slower than subsequent calls due to the fact that &lt;code&gt;az devops&lt;/code&gt; fetches and caches information about the Azure DevOps Organization that it connects to. These calls still add about a 15s overhead. Users that want to speed up &lt;code&gt;az devops&lt;/code&gt; further could consider caching the &lt;code&gt;$env:AZURE_DEVOPS_CACHE_DIR&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Links to sources used to make this pull request:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://techcommunity.microsoft.com/t5/azure-tools-blog/streamline-configuring-azure-cli-with-az-init/ba-p/3051810" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;az init&lt;/code&gt; automation recommended settings&lt;/a&gt;. - I left out the one that only outputs errors as it is hard to see what the workflow/pipeline's doing. Ideally that setting would tigger on the diagnostics flag of the workflow.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;az-cli&lt;/code&gt; &lt;a href="https://github.com/Azure/azure-cli/blob/0a62d499ac898dcc9227e055ba48cf7c44ccbd0c/src/azure-cli-core/azure/cli/core/_environment.py#L9" rel="noopener noreferrer"&gt;configuration directory environment variable is defined here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;az devops&lt;/code&gt; &lt;a href="https://github.com/Azure/azure-devops-cli-extension/blob/bd34a6fd0658a15dadf6c09c7f6217ca5ffa662b/scripts/dev_setup.py#L12" rel="noopener noreferrer"&gt;configuration environment variable is defined here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;az devops&lt;/code&gt; cache environment variable is defined in multiple places, &lt;a href="https://github.com/Azure/azure-devops-cli-extension/blob/bd34a6fd0658a15dadf6c09c7f6217ca5ffa662b/azure-devops/azext_devops/devops_sdk/_file_cache.py#L114" rel="noopener noreferrer"&gt;it sometimes keys off of the configuration environment variable&lt;/a&gt; but &lt;a href="https://github.com/Azure/azure-devops-cli-extension/blob/bd34a6fd0658a15dadf6c09c7f6217ca5ffa662b/azure-devops/azext_devops/devops_sdk/_file_cache.py#L114" rel="noopener noreferrer"&gt;sometimes it's hardcoded against the home directory&lt;/a&gt; if the environment variable isn't defined. Filed: &lt;a href="https://github.com/Azure/azure-devops-cli-extension/issues/1366" rel="noopener noreferrer"&gt;https://github.com/Azure/azure-devops-cli-extension/issues/1366&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Technically changing any default configuration settings can be breaking. My personal view on these settings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;az config set auto-upgrade.enable=false&lt;/code&gt; - should not break anyone. The hosted image is updated regularly enough that it should not be needed to auto-upgrade az-cli during a workflow/pipeline run.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;az config set core.error_recommendation=off&lt;/code&gt; - should not break anyone. Worst case it makes debugging scripts a little harder, though running the same script locally should still provide recommendations.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;az config set core.disable_progress_bar=true&lt;/code&gt; - progress bars don't work in the hosted runner anyway.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;az config set core.no_color=true&lt;/code&gt; - will make the logs less pretty, &lt;a href="https://github.com/microsoft/azure-pipelines-agent/issues/1569" rel="noopener noreferrer"&gt;but also fixes issues where certain ascii colors aren't coming through correctly&lt;/a&gt;. Should not really break anyone.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;az config set core.survey_message=false&lt;/code&gt; - &lt;a href="https://github.com/Azure/azure-cli/issues/25242" rel="noopener noreferrer"&gt;This setting suppresses the survey links that the CLI sometimes outputs&lt;/a&gt;, they have no place in a pipeline or workflow anyway.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I had already removed the settings from the suggestions made by &lt;code&gt;az init&lt;/code&gt; and left them on default:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;az config set logging.enable_log_file=no&lt;/code&gt; - I personally don't rely on the log file, &lt;strong&gt;I suppose someone could. This might be the most breaking change in the list.&lt;/strong&gt;. There is anecdotal evidence in other github issues that suggests file logging slows down az-cli. I'd prefer to make it opt in. The less the agent does by default the better.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;az config set only_show_errors=true&lt;/code&gt; - technically not a breaking change and making the log less chatty. I removed this cause I feel it makes it harder to see what the cli is and isn't doing. Ideally this flag would be set based on the diagnostic settings of the pipeline itself.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;az config set collect_telemetry=false&lt;/code&gt; - though there is a lot of anecdotal evidence that telemetry slows down &lt;code&gt;az&lt;/code&gt; or some of its extensions, I imagine the cli team would like to get telemetry from the hosted runners.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;People who want to save a little more time can opt to add these settings to their pipeline/workflow.&lt;/p&gt;
&lt;h4 id="user-content-related-issue"&gt;Related issue:&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h4&gt;
&lt;p&gt;Fixes: #8296?&lt;/p&gt;
&lt;h2 id="user-content-check-list"&gt;Check list&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[x] Related issue / work item is attached&lt;/li&gt;
&lt;li&gt;[ ] Tests are written (if applicable)&lt;/li&gt;
&lt;li&gt;[ ] Documentation is updated (if applicable)&lt;/li&gt;
&lt;li&gt;[x] Changes are tested and related VM images are successfully generated&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/actions/runner-images/pull/8294" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  First run of az on hosted runner causes python compilation
&lt;/h2&gt;

&lt;p&gt;Because the image generation code never actually runs &lt;code&gt;az&lt;/code&gt; and &lt;code&gt;az devops&lt;/code&gt; and because the &lt;code&gt;~/.azure&lt;/code&gt; directory and &lt;code&gt;~/.azure-devops&lt;/code&gt; aren't made available to the user that runs the workflow; the first run compiles several python modules and caches the result.&lt;/p&gt;

&lt;p&gt;This is also fixed by setting environment variables and calling &lt;code&gt;az --help&lt;/code&gt; and &lt;code&gt;az devops --help&lt;/code&gt; during image generation.&lt;/p&gt;

&lt;p&gt;Submitted a pull request to move these folders to a persistent location and warm-up &lt;code&gt;az&lt;/code&gt; and &lt;code&gt;az devops&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;%{ embed &lt;a href="https://github.com/actions/runner-images/pull/8294" rel="noopener noreferrer"&gt;https://github.com/actions/runner-images/pull/8294&lt;/a&gt; %}&lt;/p&gt;

&lt;p&gt;Some of the data that &lt;code&gt;az devops&lt;/code&gt; needs isn't stored under &lt;code&gt;~/.azure&lt;/code&gt;, but has its own config path under &lt;code&gt;~/.azure-devops&lt;/code&gt;. While trying to redirect that folder and the underlying &lt;code&gt;./python/cache&lt;/code&gt; folder I found out that not all the ways you can redirect these folders have the exact same effect, because the cache folder location is computed in different ways.&lt;/p&gt;

&lt;p&gt;So, I filed another issue:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/Azure/azure-devops-cli-extension/issues/1366" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Bug: the azure-devops cache folder location is computed differently in different places
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#1366&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F4173387%3Fv%3D4" alt="jessehouwing avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;jessehouwing&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/Azure/azure-devops-cli-extension/issues/1366" rel="noopener noreferrer"&gt;&lt;time&gt;Sep 20, 2023&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;The Azure DevOps CLI has a way to redirect the config and the cache directory to a different location.&lt;/p&gt;
&lt;p&gt;In most code paths it's enough to only redirect the CONFIG directory and in that case the cache folder will automatically be placed underneath the config folder.&lt;/p&gt;
&lt;p&gt;But there are a few places in which the cache folder is placed under the home directory instead.&lt;/p&gt;
&lt;p&gt;Under home
&lt;a href="https://github.com/Azure/azure-devops-cli-extension/blob/bd34a6fd0658a15dadf6c09c7f6217ca5ffa662b/azure-devops/azext_devops/devops_sdk/_file_cache.py#L114" rel="noopener noreferrer"&gt;https://github.com/Azure/azure-devops-cli-extension/blob/bd34a6fd0658a15dadf6c09c7f6217ca5ffa662b/azure-devops/azext_devops/devops_sdk/_file_cache.py#L114&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Under config
&lt;a href="https://github.com/Azure/azure-devops-cli-extension/blob/bd34a6fd0658a15dadf6c09c7f6217ca5ffa662b/azure-devops/azext_devops/dev/common/file_cache.py#L15" rel="noopener noreferrer"&gt;https://github.com/Azure/azure-devops-cli-extension/blob/bd34a6fd0658a15dadf6c09c7f6217ca5ffa662b/azure-devops/azext_devops/dev/common/file_cache.py#L15&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I'd expect a single consistent behavior.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/search?q=repo%3AAzure%2Fazure-devops-cli-extension+os.getenv&amp;amp;type=code" rel="noopener noreferrer"&gt;https://github.com/search?q=repo%3AAzure%2Fazure-devops-cli-extension+os.getenv&amp;amp;type=code&lt;/a&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Azure/azure-devops-cli-extension/issues/1366" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Default configuration of &lt;code&gt;az&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The default configuration of &lt;code&gt;az&lt;/code&gt; leaves several settings enabled or unconfigured:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Telemetry&lt;/li&gt;
&lt;li&gt;Disk logging&lt;/li&gt;
&lt;li&gt;Progress bars&lt;/li&gt;
&lt;li&gt;Console colors&lt;/li&gt;
&lt;li&gt;Survey prompts&lt;/li&gt;
&lt;li&gt;Auto-upgrade&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a pretty unknown &lt;code&gt;az init&lt;/code&gt; command which will prompt whether you want to run in an interactive or an automation environment and it forces a number of these settings to off.&lt;/p&gt;

&lt;p&gt;So, I filed a pull request to do the same thing on the Hosted Runner:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/actions/runner-images/pull/8294" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Runs az and az-devops during warmup
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#8294&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F4173387%3Fv%3D4" alt="jessehouwing avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;jessehouwing&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/actions/runner-images/pull/8294" rel="noopener noreferrer"&gt;&lt;time&gt;Sep 14, 2023&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;h1 id="user-content-description"&gt;Description&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h1&gt;
&lt;p&gt;Speed up performance of &lt;code&gt;az&lt;/code&gt; and &lt;code&gt;az devops&lt;/code&gt;. In my own experiments savings are sometimes more than 60 seconds.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;This is done by changing the default settings of &lt;code&gt;az&lt;/code&gt; based on the recommended settings from &lt;code&gt;az init&lt;/code&gt; for automation workflows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enables the settings recommended by &lt;code&gt;az init&lt;/code&gt; for automation workflows.&lt;/li&gt;
&lt;li&gt;Disables auto-upgrade&lt;/li&gt;
&lt;li&gt;Disables colors&lt;/li&gt;
&lt;li&gt;Disables surveys&lt;/li&gt;
&lt;li&gt;Disables progress bars&lt;/li&gt;
&lt;li&gt;Disables recommendations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It invokes &lt;code&gt;az&lt;/code&gt; and &lt;code&gt;az devops&lt;/code&gt; during the image build to ensure Python pre-caches its objects.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It moves the &lt;code&gt;.azure&lt;/code&gt; and &lt;code&gt;.azure-devops&lt;/code&gt; and &lt;code&gt;.azure-devops/cache&lt;/code&gt; folders into the CommonFiles directory similarly to how the runner already moved installed extensions to the CommonFiles directory.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First call performance, especially of &lt;code&gt;az devops&lt;/code&gt; commands will still be slower than subsequent calls due to the fact that &lt;code&gt;az devops&lt;/code&gt; fetches and caches information about the Azure DevOps Organization that it connects to. These calls still add about a 15s overhead. Users that want to speed up &lt;code&gt;az devops&lt;/code&gt; further could consider caching the &lt;code&gt;$env:AZURE_DEVOPS_CACHE_DIR&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Links to sources used to make this pull request:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://techcommunity.microsoft.com/t5/azure-tools-blog/streamline-configuring-azure-cli-with-az-init/ba-p/3051810" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;az init&lt;/code&gt; automation recommended settings&lt;/a&gt;. - I left out the one that only outputs errors as it is hard to see what the workflow/pipeline's doing. Ideally that setting would tigger on the diagnostics flag of the workflow.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;az-cli&lt;/code&gt; &lt;a href="https://github.com/Azure/azure-cli/blob/0a62d499ac898dcc9227e055ba48cf7c44ccbd0c/src/azure-cli-core/azure/cli/core/_environment.py#L9" rel="noopener noreferrer"&gt;configuration directory environment variable is defined here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;az devops&lt;/code&gt; &lt;a href="https://github.com/Azure/azure-devops-cli-extension/blob/bd34a6fd0658a15dadf6c09c7f6217ca5ffa662b/scripts/dev_setup.py#L12" rel="noopener noreferrer"&gt;configuration environment variable is defined here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;az devops&lt;/code&gt; cache environment variable is defined in multiple places, &lt;a href="https://github.com/Azure/azure-devops-cli-extension/blob/bd34a6fd0658a15dadf6c09c7f6217ca5ffa662b/azure-devops/azext_devops/devops_sdk/_file_cache.py#L114" rel="noopener noreferrer"&gt;it sometimes keys off of the configuration environment variable&lt;/a&gt; but &lt;a href="https://github.com/Azure/azure-devops-cli-extension/blob/bd34a6fd0658a15dadf6c09c7f6217ca5ffa662b/azure-devops/azext_devops/devops_sdk/_file_cache.py#L114" rel="noopener noreferrer"&gt;sometimes it's hardcoded against the home directory&lt;/a&gt; if the environment variable isn't defined. Filed: &lt;a href="https://github.com/Azure/azure-devops-cli-extension/issues/1366" rel="noopener noreferrer"&gt;https://github.com/Azure/azure-devops-cli-extension/issues/1366&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Technically changing any default configuration settings can be breaking. My personal view on these settings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;az config set auto-upgrade.enable=false&lt;/code&gt; - should not break anyone. The hosted image is updated regularly enough that it should not be needed to auto-upgrade az-cli during a workflow/pipeline run.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;az config set core.error_recommendation=off&lt;/code&gt; - should not break anyone. Worst case it makes debugging scripts a little harder, though running the same script locally should still provide recommendations.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;az config set core.disable_progress_bar=true&lt;/code&gt; - progress bars don't work in the hosted runner anyway.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;az config set core.no_color=true&lt;/code&gt; - will make the logs less pretty, &lt;a href="https://github.com/microsoft/azure-pipelines-agent/issues/1569" rel="noopener noreferrer"&gt;but also fixes issues where certain ascii colors aren't coming through correctly&lt;/a&gt;. Should not really break anyone.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;az config set core.survey_message=false&lt;/code&gt; - &lt;a href="https://github.com/Azure/azure-cli/issues/25242" rel="noopener noreferrer"&gt;This setting suppresses the survey links that the CLI sometimes outputs&lt;/a&gt;, they have no place in a pipeline or workflow anyway.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I had already removed the settings from the suggestions made by &lt;code&gt;az init&lt;/code&gt; and left them on default:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;az config set logging.enable_log_file=no&lt;/code&gt; - I personally don't rely on the log file, &lt;strong&gt;I suppose someone could. This might be the most breaking change in the list.&lt;/strong&gt;. There is anecdotal evidence in other github issues that suggests file logging slows down az-cli. I'd prefer to make it opt in. The less the agent does by default the better.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;az config set only_show_errors=true&lt;/code&gt; - technically not a breaking change and making the log less chatty. I removed this cause I feel it makes it harder to see what the cli is and isn't doing. Ideally this flag would be set based on the diagnostic settings of the pipeline itself.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;az config set collect_telemetry=false&lt;/code&gt; - though there is a lot of anecdotal evidence that telemetry slows down &lt;code&gt;az&lt;/code&gt; or some of its extensions, I imagine the cli team would like to get telemetry from the hosted runners.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;People who want to save a little more time can opt to add these settings to their pipeline/workflow.&lt;/p&gt;
&lt;h4 id="user-content-related-issue"&gt;Related issue:&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h4&gt;
&lt;p&gt;Fixes: #8296?&lt;/p&gt;
&lt;h2 id="user-content-check-list"&gt;Check list&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[x] Related issue / work item is attached&lt;/li&gt;
&lt;li&gt;[ ] Tests are written (if applicable)&lt;/li&gt;
&lt;li&gt;[ ] Documentation is updated (if applicable)&lt;/li&gt;
&lt;li&gt;[x] Changes are tested and related VM images are successfully generated&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/actions/runner-images/pull/8294" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;These changes are currently under consideration as they don't have the same impact as the other changes mentioned above ( &lt;strong&gt;some could be breaking&lt;/strong&gt; ). You could set these in your own workflows if you'd like.&lt;/p&gt;

&lt;p&gt;And filed a pull request to turn off auto-upgrade in &lt;code&gt;az init&lt;/code&gt; as well:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/Azure/azure-cli-extensions/pull/6793" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        configures survey messages and telemetry
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#6793&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F4173387%3Fv%3D4" alt="jessehouwing avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;jessehouwing&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/Azure/azure-cli-extensions/pull/6793" rel="noopener noreferrer"&gt;&lt;time&gt;Sep 21, 2023&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;This checklist is used to make sure that common guidelines for a pull request are followed.&lt;/p&gt;
&lt;h3 id="user-content-related-command"&gt;Related command&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;Adds settings for &lt;code&gt;[core.survey_message](https://github.com/Azure/azure-cli/issues/25242)&lt;/code&gt; and &lt;code&gt;core.collect_telemetry&lt;/code&gt; to &lt;code&gt;az init&lt;/code&gt;.
Adds the following defaults:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Manual Mode
&lt;ul&gt;
&lt;li&gt;Survey=on&lt;/li&gt;
&lt;li&gt;Telemetry=on&lt;/li&gt;
&lt;li&gt;Auto-update=on&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Automation Mode
&lt;ul&gt;
&lt;li&gt;Survey=off&lt;/li&gt;
&lt;li&gt;Telemetry=off&lt;/li&gt;
&lt;li&gt;Auto-update=off&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="user-content-general-guidelines"&gt;General Guidelines&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;[ ] Have you run &lt;code&gt;azdev style &amp;lt;YOUR_EXT&amp;gt;&lt;/code&gt; locally? (&lt;code&gt;pip install azdev&lt;/code&gt; required)&lt;/li&gt;
&lt;li&gt;[x] Have you run &lt;code&gt;python scripts/ci/test_index.py -q&lt;/code&gt; locally?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For new extensions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[x] My extension description/summary conforms to the &lt;a href="https://github.com/Azure/azure-cli/blob/dev/doc/extensions/extension_summary_guidelines.md" rel="noopener noreferrer"&gt;Extension Summary Guidelines&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="user-content-about-extension-publish"&gt;About Extension Publish&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;There is a pipeline to automatically build, upload and publish extension wheels.&lt;br&gt;
Once your pull request is merged into main branch, a new pull request will be created to update &lt;code&gt;src/index.json&lt;/code&gt; automatically.&lt;br&gt;
You only need to update the version information in file setup.py and historical information in file HISTORY.rst in your PR but do not modify &lt;code&gt;src/index.json&lt;/code&gt;.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Azure/azure-cli-extensions/pull/6793" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  &lt;code&gt;AzureCLI@2&lt;/code&gt; does a version update check
&lt;/h2&gt;

&lt;p&gt;When you use the &lt;code&gt;AzureCLI@2&lt;/code&gt; task, the first thing it does is running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az --version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Which in turn performs and update check and caches the results, but as you can guess by now, that cached result isn't available in the pristine profile of the user running your workflow.&lt;/p&gt;

&lt;p&gt;I feel that &lt;code&gt;AzureCLI@2&lt;/code&gt; has no business doing an update check anyway and it turns out that there is a second command &lt;code&gt;az version&lt;/code&gt; (note the lack of  &lt;code&gt;--&lt;/code&gt;). It mostly does the same thing but skips the update check.&lt;/p&gt;

&lt;p&gt;Filed another pull request:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/microsoft/azure-pipelines-tasks/pull/19039" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Replaces `az --version` with `az version`
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#19039&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F4173387%3Fv%3D4" alt="jessehouwing avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;jessehouwing&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/microsoft/azure-pipelines-tasks/pull/19039" rel="noopener noreferrer"&gt;&lt;time&gt;Sep 28, 2023&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;&lt;code&gt;az version&lt;/code&gt; doesn't perform an update check and is faster.&lt;/p&gt;
&lt;p&gt;Fixes: #19006&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Task name&lt;/strong&gt;: AzureCLI&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;: Replaces the call to &lt;code&gt;az --version&lt;/code&gt; with &lt;code&gt;az version&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Documentation changes required:&lt;/strong&gt; N&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Added unit tests:&lt;/strong&gt; N&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Attached related issue:&lt;/strong&gt; #19006&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Checklist&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[x] Task version was bumped - please check &lt;a href="https://github.com/microsoft/azure-pipelines-tasks/tree/master/docs/taskversionbumping.md" rel="noopener noreferrer"&gt;instruction&lt;/a&gt; how to do it&lt;/li&gt;
&lt;li&gt;[x] Checked that applied changes work as expected&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/microsoft/azure-pipelines-tasks/pull/19039" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;And while it's nice that the alternative command exists, it would seem better to me to make the version-check configurable:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/Azure/azure-cli/issues/27437" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        `az --version` performs an update check
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#27437&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F4173387%3Fv%3D4" alt="jessehouwing avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;jessehouwing&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/Azure/azure-cli/issues/27437" rel="noopener noreferrer"&gt;&lt;time&gt;Sep 20, 2023&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;h3 id="user-content-describe-the-bug"&gt;Describe the bug&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;When running &lt;code&gt;az --version&lt;/code&gt; an update check is performed against az-cli and the extensions.&lt;/p&gt;
&lt;p&gt;Azure Pipelines' AzureCLI task runs &lt;code&gt;az --version&lt;/code&gt; to capture the version details in the logs.&lt;/p&gt;
&lt;p&gt;It would save quite a bit of CPU if az-cli would not perform an update check in a CI/CD scenario.&lt;/p&gt;
&lt;p&gt;There already is an core.auto-upgrade=false option, would it not make sense to piggy back on that or to add another config setting to turn off update checking.&lt;/p&gt;
&lt;h3 id="user-content-related-command"&gt;Related command&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;az --version&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="user-content-errors"&gt;Errors&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;N/a&lt;/p&gt;
&lt;h3 id="user-content-issue-script--debug-output"&gt;Issue script &amp;amp; Debug output&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;N/a&lt;/p&gt;
&lt;h3 id="user-content-expected-behavior"&gt;Expected behavior&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;No update check is performed in CI.&lt;/p&gt;
&lt;h3 id="user-content-environment-summary"&gt;Environment Summary&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;2.52.0&lt;/p&gt;
&lt;h3 id="user-content-additional-context"&gt;Additional context&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;No response&lt;/em&gt;&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Azure/azure-cli/issues/27437" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Auto-detecting your Azure DevOps collection and Project is slower
&lt;/h2&gt;

&lt;p&gt;Many &lt;code&gt;az devops&lt;/code&gt; commands need to know the location of your Azure DevOps organization and the name of the project you're connecting to. If you don't explicitly pass these in, &lt;code&gt;az devops&lt;/code&gt; will try to run &lt;code&gt;git remote --verbose&lt;/code&gt; to look up the details. This adds another little bit of overhead.&lt;/p&gt;

&lt;p&gt;Since &lt;a href="https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&amp;amp;tabs=yaml&amp;amp;ref=jessehouwing.net" rel="noopener noreferrer"&gt;Azure Pipelines already knows the organization and the project and sets environment variables for you&lt;/a&gt;, you might as well pass them in explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- pwsh: |
    az pipelines runs show --id $env:BUILD_BUILDID --query "definition.id" `
      --organization $env:SYSTEM_COLLECTIONURI `
      --project $env:SYSTEM_TEAMPROJECT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It would be nice if &lt;code&gt;auto-detect&lt;/code&gt; would use these environment variables if they are available. Haven't filed an issue for that yet.&lt;/p&gt;
&lt;h2&gt;
  
  
  On Azure Pipelines everything runs inside PowerShell 5.1
&lt;/h2&gt;

&lt;p&gt;In Azure Pipelines everything except Node based tasks run inside PowerShell 5.1. Even a Windows Shell task (&lt;code&gt;CmdLine@2&lt;/code&gt;) runs inside of PowerShell 5.1:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Starting: CmdLine
==============================================================================
Task : Command line
Description : Run a command line script using Bash on Linux and macOS and cmd.exe on Windows
Version : 2.212.0
Author : Microsoft Corporation
Help : https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/command-line
==============================================================================
##[debug]VstsTaskSdk 0.9.0 commit 6c48b16164b9a1c9548776ad2062dad5cd543352
##[debug]Entering D:\a\_tasks\CmdLine_d9bafed4-0b18-4f58-968d-86655b4d2ce9\2.212.0\cmdline.ps1.
========================== Starting Command Output ===========================
##[debug]Entering Invoke-VstsTool.
##[debug] Arguments: '/D /E:ON /V:OFF /S /C "CALL "D:\a\_temp\5cf768ae-b47d-41b4-a176-02a9957e0e28.cmd""'
##[debug] FileName: 'C:\Windows\system32\cmd.exe'
##[debug] WorkingDirectory: 'D:\a\1\s'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Unlike GitHub Actions, even &lt;code&gt;pwsh&lt;/code&gt; runs inside of PowerShell 5.1 in Azure Pipelines. This makes &lt;code&gt;script:&lt;/code&gt; and &lt;code&gt;pwsh:&lt;/code&gt; and a tiny bit slower on Azure Pipelines than using &lt;code&gt;powershell:&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;But under certain conditions (like the one below), this tiny bit slower can add a quite noticeable &lt;strong&gt;6s to 10s&lt;/strong&gt; additional delay.&lt;/p&gt;

&lt;p&gt;I requested that a proper PowerShell Core Execution handler is added to the Azure Pipelines Agent.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/microsoft/azure-pipelines-agent/issues/4455" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        [enhancement]: Add PowerShell Core 7 execution handler
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#4455&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F4173387%3Fv%3D4" alt="jessehouwing avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;jessehouwing&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/microsoft/azure-pipelines-agent/issues/4455" rel="noopener noreferrer"&gt;&lt;time&gt;Sep 29, 2023&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;h3 id="user-content-describe-your-feature-request-here"&gt;Describe your feature request here&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;All tasks that use the PowerShell and PowerShell3 execution handler rely on PowerShell 5.1 as the main execution engine of the task. Any task that relies on PowerShell Core must call PowerShell Core either from PowerShell 5.1 or from Node.&lt;/p&gt;
&lt;p&gt;Back in 2015 when the agent was first introduced and PowerShell Core was mostly a gimmick, it made sense, maintaining 2 different but mostly equal execution handlers only add maintenance overhead.&lt;/p&gt;
&lt;p&gt;Fast-forward 8 years and PowerShell Core is now the gold standard. It's faster, cross platform and most new features come to it, including fancy language features. Most of all &lt;strong&gt;its cross platform&lt;/strong&gt; and it &lt;strong&gt;doesn't depend on 4MB of random node modules&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;It's time to introduce a proper &lt;code&gt;PowerShellCore&lt;/code&gt; execution handler that doesn't rely on PowerShell 5.1, that has its own VstsTaskSdk and that runs cross-platform.&lt;/p&gt;
&lt;p&gt;Why?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It's faster. In the past days I've been looking at hosted agent performance and &lt;code&gt;pwsh:&lt;/code&gt; as well as &lt;code&gt;AzureCLI&lt;/code&gt; and &lt;code&gt;AzurePowerShell&lt;/code&gt; and &lt;code&gt;PowerShell&lt;/code&gt; tasks configured to use PowerShell Core add a few seconds overhead to each task execution.&lt;/li&gt;
&lt;li&gt;It's cross platform. I'm no star in Bash nor a hero in Typescript, but I know my way around the CLR and have written quite a bit of PowerShell, let me take my skills to Linux and Mac as well.&lt;/li&gt;
&lt;li&gt;It's more secure than Node based Tasks. Node based tasks easily carry 100s of additional Node Packages to do things that are built-in to PowerShell Core. XML parsing? Json parsing? Zipping archives, XSLT, JsonPath, REST API calls, you name it. In my research I can't find any PowerShell based extension with security vulns, yet at the moment there is no Node based tasks that doesn't trigger at least 2 critical warnings.&lt;/li&gt;
&lt;li&gt;It's where the current state of the market is at. Even PowerShell itself tries to tell me every time I accidentally open the wrong shell: &lt;code&gt;Install the latest PowerShell for new features and improvements! https://aka.ms/PSWindows&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;GitHub Actions already has support for PowerShell core as default script handler and you can use PowerShell Core in composite actions to build your tasks. Having the same option in Azure Pipelines would make it easier to port tasks between the wo.&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/microsoft/azure-pipelines-agent/issues/4455" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Windows might be trying to be helpful
&lt;/h2&gt;

&lt;p&gt;While chatting with an engineer on the actions/runner-images team, we talked about a few issues that have been plaguing the hosted runner recently. It turns out that Windows Server has added a few more ways to ensure that Windows Update always runs and to run a few jobs to keep Windows performing at its best.&lt;/p&gt;

&lt;p&gt;The hosted runner images are updated very frequently and when the image runs, it only needs to run one job before it's deleted. As such, these services are disabled during the generation of the Windows runner images.&lt;/p&gt;

&lt;p&gt;Until recently that is.&lt;/p&gt;

&lt;p&gt;A change in Windows has caused the "Storage Service" and the "Windows Update Service" to be re-enabled and restarted as soon as the image boots up. And if you're unlucky they slow down the hosted runner while doing their intended job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A new image will be rolling out shortly, one that again turns off these services&lt;/strong&gt; , this time a little more forceful:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/actions/runner-images/issues/8380" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Agents very slow
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#8380&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/alminveh" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F133762074%3Fv%3D4" alt="alminveh avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/alminveh" rel="noopener noreferrer"&gt;alminveh&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/actions/runner-images/issues/8380" rel="noopener noreferrer"&gt;&lt;time&gt;Sep 25, 2023&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;h3 id="user-content-description"&gt;Description&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;Since September 21 agents are very slow. Even simple tasks that usually take 1-2 seconds now take 25-30 seconds. A comparison of some tasks from two runs can be seen below:
&lt;a rel="noopener noreferrer" href="https://github.com/actions/runner-images/assets/133762074/649ded77-ef00-450a-9c3d-fa5c3aa24c8a"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Factions%2Frunner-images%2Fassets%2F133762074%2F649ded77-ef00-450a-9c3d-fa5c3aa24c8a" alt="image"&gt;&lt;/a&gt;
On the left side we have a run before September 21 (simple tasks taking 1-2 seconds to complete), on the right side we have the same tasks running on September 25 (same tasks taking 25-30 seconds to complete.&lt;/p&gt;
&lt;h3 id="user-content-platforms-affected"&gt;Platforms affected&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;[X] Azure DevOps&lt;/li&gt;
&lt;li&gt;[ ] GitHub Actions - Standard Runners&lt;/li&gt;
&lt;li&gt;[ ] GitHub Actions - Larger Runners&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="user-content-runner-images-affected"&gt;Runner images affected&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;[ ] Ubuntu 20.04&lt;/li&gt;
&lt;li&gt;[ ] Ubuntu 22.04&lt;/li&gt;
&lt;li&gt;[ ] macOS 11&lt;/li&gt;
&lt;li&gt;[ ] macOS 12&lt;/li&gt;
&lt;li&gt;[ ] macOS 13&lt;/li&gt;
&lt;li&gt;[X] Windows Server 2019&lt;/li&gt;
&lt;li&gt;[X] Windows Server 2022&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="user-content-image-version-and-build-link"&gt;Image version and build link&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;Issue started from version 20230918.1.0&lt;/p&gt;
&lt;h3 id="user-content-is-it-regression"&gt;Is it regression?&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;20230912.1.0&lt;/p&gt;
&lt;h3 id="user-content-expected-behavior"&gt;Expected behavior&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;Tasks are fast to execute&lt;/p&gt;
&lt;h3 id="user-content-actual-behavior"&gt;Actual behavior&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;Task execution is very slow&lt;/p&gt;
&lt;h3 id="user-content-repro-steps"&gt;Repro steps&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/actions/runner-images/issues/8380" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/actions/runner-images/pull/8388" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        [windows] disable StorSvc for runners
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#8388&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/ilia-shipitsin" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F125650415%3Fv%3D4" alt="ilia-shipitsin avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/ilia-shipitsin" rel="noopener noreferrer"&gt;ilia-shipitsin&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/actions/runner-images/pull/8388" rel="noopener noreferrer"&gt;&lt;time&gt;Sep 26, 2023&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;h1 id="user-content-description"&gt;Description&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h1&gt;
&lt;p&gt;StorSvc service wakes up in 700-800 sec and scans all files, which affects runner a lot. Let us try to disable it&lt;/p&gt;
&lt;h4 id="user-content-related-issue"&gt;Related issue:&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h4&gt;
&lt;h2 id="user-content-check-list"&gt;Check list&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[ ] Related issue / work item is attached&lt;/li&gt;
&lt;li&gt;[ ] Tests are written (if applicable)&lt;/li&gt;
&lt;li&gt;[ ] Documentation is updated (if applicable)&lt;/li&gt;
&lt;li&gt;[ ] Changes are tested and related VM images are successfully generated&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/actions/runner-images/pull/8388" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;In the meantime, you can use this snippet in your workflow to turn these services back off:&lt;/p&gt;

&lt;h3&gt;
  
  
  Azure Pipelines:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 🔁 Azure Pipelines
steps: 
  - pwsh: |
      $services = @("WaasMedicSvc", "StorSvc", "wuauserv")

      $services | %{
        $action = "''/30000/''/30000/''/30000"
        $output = sc.exe failure $_ actions=$action reset=4000

        stop-service $_ -force
        if ($_ -ne "WaasMedicSvc")
        {
          Set-Service -StartupType Disabled $_
        }

        if ((get-service $_).Status -ne "Stopped")
        {
          $id = Get-CimInstance -Class Win32_Service -Filter "Name LIKE '$_'" | 
          Select-Object -ExpandProperty ProcessId
          $process = Get-Process -Id $id
          $process.Kill()
        }
      }

      $services | %{
        write-host $_ $((get-service $_).Status)
      }

  - checkout: self
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  GitHub Actions:
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ▶️ GitHub Actions
steps: 
  - script: |
      $services = @("WaasMedicSvc", "StorSvc", "wuauserv")

      $services | %{
        $action = "''/30000/''/30000/''/30000"
        $output = sc.exe failure $_ actions=$action reset=4000

        stop-service $_ -force
        if ($_ -ne "WaasMedicSvc")
        {
          Set-Service -StartupType Disabled $_
        }

        if ((get-service $_).Status -ne "Stopped")
        {
          $id = Get-CimInstance -Class Win32_Service -Filter "Name LIKE '$_'" | 
          Select-Object -ExpandProperty ProcessId
          $process = Get-Process -Id $id
          $process.Kill()
        }
      }

      $services | %{
        write-host $_ $((get-service $_).Status)
      }

  - uses: actions/checkout@v4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Some people might blame &lt;em&gt;Microsoft&lt;/em&gt; in general for these issues, but of course this is an interaction caused by changes made by 2 teams with hugely different goals. Where the Windows team is trying to make Windows as secure and up to date as possible, the Runners team is trying to create an image of Windows that is as lean as it can be, up-to-date, secure, yet can run 100s of different tools ranging from .NET 4 to .NET 8 and from Python to Rust as well as Node and PHP. Strange interactions are almost impossible to prevent.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;az devops&lt;/code&gt; caches instance level data
&lt;/h2&gt;

&lt;p&gt;Whenever you connect to an Azure DevOps Organization, &lt;code&gt;az devops&lt;/code&gt; will make 2 calls:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OPTIONS /{{organization}/_apis
GET /{organization}/_apis/ResourceAreas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;These calls return all the endpoints and their calling convention. But these are unlikely to change often. I've seen these calls adding 10-30s to the first call to &lt;code&gt;az devops&lt;/code&gt; that make an API call. So, I went looking for ways to cache the data.&lt;/p&gt;

&lt;p&gt;I haven't found the ideal solution yet, but this is a working prototype that will make &lt;code&gt;az devops&lt;/code&gt; reuse the data from a previous workflow run:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ⚠️ WARNING work in progress
steps:
    - task: Cache@2
      inputs:
        key: '".az-devops"'
        path: 'C:\Users\VssAdministrator\.azure-devops'
      displayName: "Restore .azure-devops"

    - pwsh: |
        (dir C:\Users\VssAdministrator\.azure-devops\python-sdk\cache\*.json) | %{$_.LastWriteTime = Get-Date} 
      displayName: "Reset last modified on .azure-devops/cache"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Unfortunately, it doesn't work under all circumstances yet as the files may not always be there.  And the pull request that will change the location of the &lt;code&gt;.azure-devops&lt;/code&gt; folder, will change the paths in the snippet above.&lt;/p&gt;

&lt;p&gt;It might be worth creating a custom task that caches these files. Unfortunately, custom tasks can't seem to access the cache in Azure Pipelines (or at least not through a mechanism in the agent or task-lib)&lt;/p&gt;

&lt;p&gt;I've filed an issue to allow tasks to cache data:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/microsoft/azure-pipelines-agent/issues/4440" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        [enhancement]: Add support for caching from an arbitrary task
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#4440&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F4173387%3Fv%3D4" alt="jessehouwing avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;jessehouwing&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/microsoft/azure-pipelines-agent/issues/4440" rel="noopener noreferrer"&gt;&lt;time&gt;Sep 18, 2023&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;h3 id="user-content-describe-your-feature-request-here"&gt;Describe your feature request here&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;For my azure pipelines extension, I'd like to be able to cache a few files to speed up future executions.&lt;/p&gt;
&lt;p&gt;Right now, that's only possible if the user adds a &lt;code&gt;Cache@2&lt;/code&gt; task to their pipeline where needed preceded by a script step to calculate cache keys and decide whether to run the step or not.&lt;/p&gt;
&lt;p&gt;This logic is &lt;em&gt;MUCH&lt;/em&gt; easier to do inside my own task, as I'd be able to handle everything from there.&lt;/p&gt;
&lt;p&gt;My proposal is to add a tasklib function similar to the ones used by &lt;a href="https://github.com/actions/setup-node/tree/main/src" rel="noopener noreferrer"&gt;GitHub Action's setup-node&lt;/a&gt; step.&lt;/p&gt;
&lt;p&gt;Ideally it would use the same efficient mechanism as the current Cache steps, but would allow me to have influence over whether to overwrite the cache at the end of the job or not.&lt;/p&gt;
&lt;p&gt;I'd use this to also cache files that can't compute the cache key based on the contents of the repo. Instead, I'd use the return value of an API call or check whether the files to cache have changed since the last run.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/microsoft/azure-pipelines-agent/issues/4440" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You can see results of all these changes below:&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%2Fl3v21z9vvs7dqn67y05z.png" 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%2Fl3v21z9vvs7dqn67y05z.png" alt="Investigating az-cli performance on the hosted Azure Pipelines and GitHub Runners" width="800" height="411"&gt;&lt;/a&gt;&lt;br&gt;
_Compare the execution time with the cached files (&lt;code&gt;-on&lt;/code&gt;) and without them (&lt;code&gt;-off&lt;/code&gt;). _&lt;/p&gt;

&lt;p&gt;The combined set of changes reduces the time it takes to run &lt;code&gt;az&lt;/code&gt; for the first time in a workflow by about &lt;strong&gt;1 minute&lt;/strong&gt;. Even with the added overhead of setting up the user profile the whole workflow is faster.&lt;/p&gt;

&lt;p&gt;Some of these issues aren't exclusive to Windows either. The case sensitivity issue, keyring installation, Azure CLI's default settings and auto-detection of Azure DevOps Organization &lt;strong&gt;apply to Ubuntu and MacOS runners too&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you want to tinker a bit with these things yourself, &lt;a href="https://gist.github.com/jessehouwing/4684f372300016d76e079d926fa6385c?ref=jessehouwing.net" rel="noopener noreferrer"&gt;here is an Azure Pipelines file that I used to test most of these scenarios&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Hosted Runner is a complex thing. It's built for convenience and has 100s of tools preinstalled on it. Many of these tools have funny interactions with each other. All of those are running an operating system that is also constantly changing.&lt;/p&gt;

&lt;p&gt;Many of the tools we rely on to develop and deploy our code are flexible, extensible, and configurable and aren't always designed to run on a temporary server that executes the tool just once.&lt;/p&gt;

&lt;p&gt;At the same time, &lt;code&gt;az&lt;/code&gt; must run thousands, if not millions of times each day on the Windows Hosted runners and the issues above cause it to regularly run more than a minute longer than needed. I'm hoping that the work I've put in this week will not only speed up your workflows, but will save us all money. And - above all - it will hopefully reduce carbon emissions and water usage.&lt;/p&gt;

&lt;p&gt;This investigation dug mostly into a single tool and its extensions. &lt;strong&gt;There may be an unknown number of similar issues lurking in the set of tools you rely on. Please do take the time to investigate and file issues, submit pull requests, and help improve these systems for all of us.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A huge shoutout to &lt;a href="https://github.com/ilia-shipitsin?ref=jessehouwing.net" rel="noopener noreferrer"&gt;ilia-shipitsin&lt;/a&gt; for looking into these issues and testing them on actual hosted runners.&lt;/p&gt;

&lt;p&gt;If these fixes are making your pipelines a little faster, &lt;a href="https://github.com/sponsors/jessehouwing/" rel="noopener noreferrer"&gt;consider sponsoring me to allow me to do these kinds of things more often&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>github</category>
      <category>githubactions</category>
      <category>azurepipelines</category>
      <category>azuredevops</category>
    </item>
    <item>
      <title>VSBuild task fails on self-hosted Azure Pipelines Agent</title>
      <dc:creator>Jesse Houwing</dc:creator>
      <pubDate>Mon, 18 Sep 2023 13:37:29 +0000</pubDate>
      <link>https://dev.to/xebia/vsbuild-task-fails-on-self-hosted-azure-pipelines-agent-57no</link>
      <guid>https://dev.to/xebia/vsbuild-task-fails-on-self-hosted-azure-pipelines-agent-57no</guid>
      <description>&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%2Ffwk6wo24kzhdy6wdz3ld.png" 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%2Ffwk6wo24kzhdy6wdz3ld.png" alt="VSBuild task fails on self-hosted Azure Pipelines Agent" width="741" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today I got this baffling error while trying to run one of the few pipelines I own that requires a self-hosted agent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2023-09-18T13:24:55.1897667Z ##[section]Starting: VSBuild
2023-09-18T13:24:55.2042232Z ==============================================================================
2023-09-18T13:24:55.2042611Z Task : Visual Studio build
2023-09-18T13:24:55.2042705Z Description : Build with MSBuild and set the Visual Studio version property
2023-09-18T13:24:55.2042827Z Version : 1.214.0
2023-09-18T13:24:55.2042907Z Author : Microsoft Corporation
2023-09-18T13:24:55.2042985Z Help : https://docs.microsoft.com/azure/devops/pipelines/tasks/build/visual-studio-build
2023-09-18T13:24:55.2043127Z ==============================================================================
2023-09-18T13:24:56.8956825Z ##[error]The following error occurred while loading the extended type data file: Error in TypeData "System.Security.AccessControl.ObjectSecurity": The member AuditToString is already present.
Error in TypeData "System.Security.AccessControl.ObjectSecurity": The member AccessToString is already present.
Error in TypeData "System.Security.AccessControl.ObjectSecurity": The member Sddl is already present.
Error in TypeData "System.Security.AccessControl.ObjectSecurity": The member Access is already present.
Error in TypeData "System.Security.AccessControl.ObjectSecurity": The member Group is already present.
Error in TypeData "System.Security.AccessControl.ObjectSecurity": The member Owner is already present.
Error in TypeData "System.Security.AccessControl.ObjectSecurity": The member Path is already present.

2023-09-18T13:24:57.0291684Z ##[error]The 'ConvertTo-SecureString' command was found in the module 'Microsoft.PowerShell.Security', but the module could not be loaded. For more information, run 'Import-Module Microsoft.PowerShell.Security'.
2023-09-18T13:24:57.0552980Z ##[section]Finishing: VSBuild
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I don't run this pipeline often and had re-imaged my laptop since the last run in March 2023... And was stumped by the error message. Googling a bit led me to a pretty old &lt;a href="https://github.com/PowerShell/PowerShell/issues/18530?ref=jessehouwing.net#issuecomment-1325691850" rel="noopener noreferrer"&gt;GitHub issue which explains the problem might happen in you run a PowerShell script in a PowerShell 5.1 terminal a Windows Command Prompt in a PowerShell Core terminal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But I wasn't, was I?!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After some more head scratching, I figured it out. I was running my Azure Pipelines agent Interactively and had launched it from a PowerShell 7 terminal. terminating the agent, opening a Windows Command prompt, and relaunching the agent fixed things.&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/microsoft/azure-pipelines-agent/issues/4438" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        [BUG]: launching self-hosted agent from powershell core prompt causes powershell-based tasks to fail
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#4438&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F4173387%3Fv%3D4" alt="jessehouwing avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/jessehouwing" rel="noopener noreferrer"&gt;jessehouwing&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/microsoft/azure-pipelines-agent/issues/4438" rel="noopener noreferrer"&gt;&lt;time&gt;Sep 18, 2023&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;h3 id="user-content-what-happened"&gt;What happened?&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;I provisioned a new self-hosted agent and ran it interactively using &lt;code&gt;./run.cmd&lt;/code&gt; from a &lt;code&gt;pwsh&lt;/code&gt; prompt in my system. All jobs containing a powershell based task fail with obscure error messages:&lt;/p&gt;
&lt;p&gt;See: &lt;a href="https://jessehouwing.net/vsbuild-task-fails-on-self-hosted-azure-pipelines-agent/" rel="nofollow noopener noreferrer"&gt;https://jessehouwing.net/vsbuild-task-fails-on-self-hosted-azure-pipelines-agent/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Turns out this is caused by launching the agent from a powershell core prompt. Stopping the agent and starting it from PowerShell 5.1 or from a Windows Shell solves the issue. Would be nice if the agent detected this and would fail to start with a proper error message.&lt;/p&gt;
&lt;h3 id="user-content-versions"&gt;Versions&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;Azure DevOps Service
Windows 11 version 22H2 (0S Build 22621.2283)
Azure Pipelines Agent 3.225.0
VSBuild task: 1.214.0&lt;/p&gt;
&lt;h3 id="user-content-environment-type-please-select-at-least-one-enviroment-where-you-face-this-issue"&gt;Environment type (Please select at least one enviroment where you face this issue)&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;[X] Self-Hosted&lt;/li&gt;
&lt;li&gt;[ ] Microsoft Hosted&lt;/li&gt;
&lt;li&gt;[ ] VMSS Pool&lt;/li&gt;
&lt;li&gt;[ ] Container&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="user-content-azure-devops-server-type"&gt;Azure DevOps Server type&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;dev.azure.com (formerly visualstudio.com)&lt;/p&gt;
&lt;h3 id="user-content-azure-devops-server-version-if-applicable"&gt;Azure DevOps Server Version (if applicable)&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;No response&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="user-content-operation-system"&gt;Operation system&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;Windows 11 version 22H2 (0S Build 22621.2283)&lt;/p&gt;
&lt;h3 id="user-content-version-controll-system"&gt;Version controll system&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;p&gt;Git&lt;/p&gt;
&lt;h3 id="user-content-relevant-log-output"&gt;Relevant log output&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;
&lt;/h3&gt;
&lt;div class="highlight highlight-source-shell js-code-highlight"&gt;
&lt;pre&gt;2023-09-18T13:24:55.1897667Z &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt;#[section]Starting: VSBuild&lt;/span&gt;
2023-09-18T13:24:55.2042232Z ==============================================================================
2023-09-18T13:24:55.2042611Z Task         &lt;span class="pl-c1"&gt;:&lt;/span&gt; Visual Studio build
2023-09-18T13:24:55.2042705Z Description  &lt;span class="pl-c1"&gt;:&lt;/span&gt; Build with MSBuild and &lt;span class="pl-c1"&gt;set&lt;/span&gt; the Visual Studio version property
2023-09-18T13:24:55.2042827Z Version      &lt;span class="pl-c1"&gt;:&lt;/span&gt; 1.214.0
2023-09-18T13:24:55.2042907Z Author       &lt;span class="pl-c1"&gt;:&lt;/span&gt; Microsoft Corporation
2023-09-18T13:24:55.2042985Z Help         &lt;span class="pl-c1"&gt;:&lt;/span&gt; https://docs.microsoft.com/azure/devops/pipelines/tasks/build/visual-studio-build
2023-09-18T13:24:55.2043127Z ==============================================================================
2023-09-18T13:24:56.8956825Z &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt;#[error]The following error occurred while loading the extended type data file: Error in TypeData "System.Security.AccessControl.ObjectSecurity": The member AuditToString is already present.&lt;/span&gt;
Error &lt;span class="pl-k"&gt;in&lt;/span&gt; TypeData &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;System.Security.AccessControl.ObjectSecurity&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: The member AccessToString is already present.
Error &lt;span class="pl-k"&gt;in&lt;/span&gt; TypeData &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;System.Security.AccessControl.ObjectSecurity&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: The member Sddl is already present.
Error &lt;span class="pl-k"&gt;in&lt;/span&gt; TypeData &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;System.Security.AccessControl.ObjectSecurity&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: The member Access is already present.
Error &lt;span class="pl-k"&gt;in&lt;/span&gt; TypeData &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;System.Security.AccessControl.ObjectSecurity&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: The member Group is already present.
Error &lt;span class="pl-k"&gt;in&lt;/span&gt; TypeData &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;System.Security.AccessControl.ObjectSecurity&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: The member Owner is already present.
Error &lt;span class="pl-k"&gt;in&lt;/span&gt; TypeData &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;System.Security.AccessControl.ObjectSecurity&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: The member Path is already present.

2023-09-18T13:24:57.0291684Z &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt;#[error]The 'ConvertTo-SecureString' command was found in the module 'Microsoft.PowerShell.Security', but the module could not be loaded. For more information, run 'Import-Module Microsoft.PowerShell.Security'.&lt;/span&gt;
2023-09-18T13:24:57.0552980Z &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt;#[section]Finishing: VSBuild&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/microsoft/azure-pipelines-agent/issues/4438" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Workaround:
&lt;/h2&gt;

&lt;p&gt;Set the agent knob &lt;code&gt;AZP_AGENT_CLEANUP_PSMODULES_IN_POWERSHELL&lt;/code&gt; on the agent prior to launching the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$env:AZP_AGENT_CLEANUP_PSMODULES_IN_POWERSHELL="true"
.\run.cmd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also add this as a variable to your pipeline.&lt;/p&gt;

</description>
      <category>azuredevopspipelines</category>
      <category>azurepipelines</category>
      <category>azuredevops</category>
    </item>
    <item>
      <title>Protect the repository hosting your GitHub Action</title>
      <dc:creator>Jesse Houwing</dc:creator>
      <pubDate>Thu, 14 Sep 2023 21:17:53 +0000</pubDate>
      <link>https://dev.to/xebia/protect-the-repository-hosting-your-github-action-1855</link>
      <guid>https://dev.to/xebia/protect-the-repository-hosting-your-github-action-1855</guid>
      <description>&lt;p&gt;Cover &lt;a href="https://www.flickr.com/photos/jono2k5/504886535" rel="noopener noreferrer"&gt;photo used under Creative Commons&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It comes as no surprise that the tags and branches solution to version GitHub Actions is weak at best. There have been rumors of Actions moving to a different model (GitHub Container Registry), but that is yet to see the light.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.paloaltonetworks.com/blog/cloud-security/github-actions-worm-dependencies/?ref=jessehouwing.net" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.paloaltonetworks.com%2Fblog%2Fwp-content%2Fuploads%2F2023%2F09%2Fword-image-304009-1.png" height="419" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.paloaltonetworks.com/blog/cloud-security/github-actions-worm-dependencies/?ref=jessehouwing.net" rel="noopener noreferrer" class="c-link"&gt;
            The GitHub Actions Worm: Compromising GitHub Repositories Through the Actions Dependency Tree
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            GitHub Actions worm compromises GitHub repositories via action dependencies in a novel attack vector allowing attackers to distribute malware across repositories, research shows.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.paloaltonetworks.com%2Fetc%2Fclientlibs%2Fpan%2Fimg%2Ffavicons2020%2Ffavicon-32x32.png" width="32" height="32"&gt;
          paloaltonetworks.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;To protect your GitHub Actions repository there are a few things the author of an Action should do.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Setup 2FA
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication?ref=jessehouwing.net" rel="noopener noreferrer"&gt;author of a GitHub Action should &lt;em&gt;always&lt;/em&gt; enable 2FA for their account&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You could consider putting all your actions in a &lt;a href="https://docs.github.com/en/organizations/keeping-your-organization-secure/managing-two-factor-authentication-for-your-organization/requiring-two-factor-authentication-in-your-organization" rel="noopener noreferrer"&gt;GitHub Organization instead of your personal account, which enables a number of extra policies (like enforced 2FA)&lt;/a&gt;. This will also allow you to enable the &lt;strong&gt;✅ verified creator&lt;/strong&gt; on your marketplace listing.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Limit default permissions of your Actions in your repo
&lt;/h2&gt;

&lt;p&gt;In the Actions settings you can limit what actions can do by default, requiring the author to set explicit permissions thus reducing the default permissions of your workflows.&lt;/p&gt;

&lt;p&gt;Limit the actions the repo is permitted to run to the exact list of actions used by your repository:&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%2Fz415m1gps3opfj6wfgt8.png" 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%2Fz415m1gps3opfj6wfgt8.png" alt="Protect the repository hosting your GitHub Action" width="781" height="557"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can further limit what a GitHub Actions workflow can do. Recommended settings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Require approval for all outside collaborator&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read repository contents and package permissions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Do &lt;strong&gt;not&lt;/strong&gt; allow &lt;strong&gt;GitHub Actions to create and approve pull requests&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&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%2Fx368qmennqh1mzu96uij.png" 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%2Fx368qmennqh1mzu96uij.png" alt="Protect the repository hosting your GitHub Action" width="800" height="564"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Setup tag protection
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/managing-repository-settings/configuring-tag-protection-rules?ref=jessehouwing.net" rel="noopener noreferrer"&gt;Setup protected tags to limit who can overwrite your tags&lt;/a&gt;. This will prevent GitHub Actions workflows from overwriting existing tags. It won't prevent the creation of new minor versions though. Major versions will need to be updated by a repository owner or a GitHub App token with Repository Admin permissions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Unfortunately, the tag name format doesn't support regular expressions. To not block the creation of a tag called &lt;code&gt;verify-sanity&lt;/code&gt; or any other tag name that starts with a &lt;code&gt;v&lt;/code&gt;, I've added the protections for all the ways a version tag can be named in GitHub Actions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Create a protected tag for &lt;code&gt;v0&lt;/code&gt; to &lt;code&gt;v9&lt;/code&gt; as well as &lt;code&gt;v*.*&lt;/code&gt; and &lt;code&gt;v*.*.*&lt;/code&gt;.&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%2Foe19dkke80j2hzx53f6s.png" 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%2Foe19dkke80j2hzx53f6s.png" alt="Protect the repository hosting your GitHub Action" width="783" height="970"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Setup Branch protection
&lt;/h2&gt;

&lt;p&gt;With the new Ruleset feature you can limit the branches that can be created. GitHub Actions will favor a branch with the name &lt;code&gt;v1&lt;/code&gt; over a tag with the same name. Thus, a new branch could be used to redirect users of your action to a different implementation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Unfortunately, the branch format doesn't support regular expressions. To not block the creation of a branch called &lt;code&gt;verify-sanity&lt;/code&gt; or any other branch name that starts with a &lt;code&gt;v&lt;/code&gt;, I've added the protections for all the ways a version tag can be named in GitHub Actions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Create a new Rule named "Do not allow versioned branches" and a rule for &lt;code&gt;v0&lt;/code&gt; to &lt;code&gt;v9&lt;/code&gt;:&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%2Fjk27j6eim205roor49cn.png" 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%2Fjk27j6eim205roor49cn.png" alt="Protect the repository hosting your GitHub Action" width="779" height="953"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Configure the policy to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Restrict creation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Restrict updates&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Block force pushes&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&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%2Ff56shwpepqvjmzae0tt1.png" 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%2Ff56shwpepqvjmzae0tt1.png" alt="Protect the repository hosting your GitHub Action" width="777" height="741"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also be sure to setup a Branch Protection for your main branch. Personally, I've setup the following rules:&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%2Fak1dsdo5y5husxriup74.png" 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%2Fak1dsdo5y5husxriup74.png" alt="Protect the repository hosting your GitHub Action" width="779" height="712"&gt;&lt;/a&gt;&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%2Fs42qwkku9jpfzx0blunv.png" 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%2Fs42qwkku9jpfzx0blunv.png" alt="Protect the repository hosting your GitHub Action" width="777" height="82"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have more than one maintainer, you block everyone from bypassing these rules. If you're a lone maintainer like me, you'll have to allow yourself to bypass this protection.&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%2Ff03hapuo5mi2vcmx25db.png" 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%2Ff03hapuo5mi2vcmx25db.png" alt="Protect the repository hosting your GitHub Action" width="779" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Setup GitHub's security features
&lt;/h2&gt;

&lt;p&gt;Enable Secret Scanning and push protection:&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%2Fz2x9cc68n7gpgg2mn7b8.png" 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%2Fz2x9cc68n7gpgg2mn7b8.png" alt="Protect the repository hosting your GitHub Action" width="790" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enable Dependabot Alerts and Version Updates:&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%2Fgmaduprhia74ing2crpb.png" 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%2Fgmaduprhia74ing2crpb.png" alt="Protect the repository hosting your GitHub Action" width="780" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a &lt;code&gt;.github/dependabot.yml&lt;/code&gt; to your Actions's repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: 2
updates:
  - package-ecosystem: "github-actions" 
    directory: "/" # Location of package manifests
    schedule:
      interval: "weekly"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Use GitHub App Tokens or Fine-grained Access Tokens
&lt;/h2&gt;

&lt;p&gt;Now that the &lt;a href="https://github.blog/changelog/2023-04-27-graphql-improvements-for-fine-grained-pats-and-github-apps?ref=jessehouwing.net" rel="noopener noreferrer"&gt;Fine-grained personal access tokens support both the REST and the GraphQL API&lt;/a&gt;, be sure to delete any remaining Classic Personal Access Tokens and replace them with a Fine-grained token with only the scopes, organisations and repositories needed by the token.&lt;/p&gt;

&lt;p&gt;Where possible limit the token to &lt;strong&gt;Only select repositories&lt;/strong&gt; :&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%2F4ufsv5ove8tr2vfm9s17.png" 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%2F4ufsv5ove8tr2vfm9s17.png" alt="Protect the repository hosting your GitHub Action" width="792" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are keeping all your actions in an organisation instead of your personal account and &lt;a href="https://docs.github.com/en/enterprise-cloud@latest/authentication/authenticating-with-saml-single-sign-on/authorizing-a-personal-access-token-for-use-with-saml-single-sign-on" rel="noopener noreferrer"&gt;have enabled Single Sign-on, then your Access tokens will require additional SSO-authorization&lt;/a&gt;. This will add yet another layer of security. &lt;a href="https://docs.github.com/en/enterprise-cloud@latest/admin/identity-and-access-management/using-saml-for-enterprise-iam/deciding-whether-to-configure-saml-for-your-enterprise-or-your-organizations" rel="noopener noreferrer"&gt;Single Sign-on is unfortunately only available for GitHub Enterprise Cloud, not on the Free and Teams plan&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In actions workflows &lt;a href="https://github.com/marketplace/actions/github-app-token?ref=jessehouwing.net" rel="noopener noreferrer"&gt;rely on GitHub Apps instead of personal acces tokens&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;steps:
- id: create_token
  uses: tibdex/github-app-token@0914d50df753bbc42180d982a6550f195390069f # v2
  with:
    app_id: ${{ secrets.APP_ID }}
    private_key: ${{ secrets.PRIVATE_KEY }}

- run: "echo 'The created token is masked: ${{ steps.create_token.outputs.token }}'"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Prefer forks to collaborate over adding collaborators to the repo
&lt;/h2&gt;

&lt;p&gt;This last item may be a bit paranoid, but GitHub protects your repository quite a bit better when other collaborators submit their changes from a fork instead of from a branch in the same repository.&lt;/p&gt;

&lt;p&gt;This way collaborators can't:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create tags&lt;/li&gt;
&lt;li&gt;Create branches&lt;/li&gt;
&lt;li&gt;Access repository secrets&lt;/li&gt;
&lt;li&gt;Run a changed workflow without approval (see policy above)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. Use &lt;code&gt;sha&lt;/code&gt; over tags in all workflows used by your own GitHub Action.
&lt;/h2&gt;

&lt;p&gt;Enable &lt;a href="https://github.com/marketplace/renovate?ref=jessehouwing.net" rel="noopener noreferrer"&gt;RenovateBot&lt;/a&gt;or &lt;a href="https://github.com/marketplace/actions/ossf-scorecard-action?ref=jessehouwing.net" rel="noopener noreferrer"&gt;OSSF Scorecard&lt;/a&gt; to automatically replace the version tags in your workflows and composite actions with their &lt;code&gt;sha&lt;/code&gt;.&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%2F2fv5a0l10wc7oahbz3xi.png" 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%2F2fv5a0l10wc7oahbz3xi.png" alt="Protect the repository hosting your GitHub Action" width="800" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.renovatebot.com/modules/manager/github-actions/?ref=jessehouwing.net" rel="noopener noreferrer"&gt;For RenovateBot add the following snippet to your &lt;code&gt;.github/renovate.json&lt;/code&gt;&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;{
  "extends": ["helpers:pinGitHubActionDigests"]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And when these tools suggest upgrading to a newer version, make sure you verify the contents of the new release.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Reduce your dependencies​
&lt;/h2&gt;

&lt;p&gt;I just went over all my own GitHub Actions and Azure Pipelines Task repositories and removed 3rd party dependencies that I didn't strictly need. For example, I had a dependency on &lt;code&gt;marvinpinto/action-automatic-releases@latest&lt;/code&gt; which I replaced with 3 lines of code in a run block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git tag latest HEAD --force
git push origin latest --force
gh release create latest --generate-notes --prerelease --latest --title "Development Build" ./ppt-diffmerge-tool/bin/Release/ppt-diffmerge.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One less dependency to worry about. This way I managed to remove most of my non-major-vendor dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Ensure your tags are versioned correctly​
&lt;/h2&gt;

&lt;p&gt;GitHub Actions requires the author of the action to manage the versioning of the action itself. It does that through tags. One set of tags should be locked down, your build/patch versions (&lt;code&gt;v1.2.x&lt;/code&gt;), the other tags are floating and should be updated every time a new build/patch version is added (&lt;code&gt;v1.x&lt;/code&gt;, &lt;code&gt;vx&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;There is no built-in mechanism to ensure the versions have been updated correctly and if &lt;code&gt;v1&lt;/code&gt; doesn't point to &lt;code&gt;v1.0.5&lt;/code&gt;, but instead still points to &lt;code&gt;v1.0.0&lt;/code&gt;, then all the people using &lt;code&gt;@v1&lt;/code&gt; of your action will forever be on the older version.&lt;/p&gt;

&lt;p&gt;To at least ensure your major version is pointing to the latest build/patch version, you can use an action I've created:Actions SemVer Checker - GitHub Marketplace Checks the version tags for your action repository to ensure the correct versions will be picked&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/marketplace/actions/actions-semver-checker" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.licdn.com%2Fdms%2Fimage%2Fsync%2FD4D27AQGyZ7834vbxGw%2Farticleshare-shrink_800%2F0%2F1699918602478%3Fe%3D1700830800%26v%3Dbeta%26t%3DHkTo6Oqnm4IUb6oACIlkbciDqKXL5WZa8qju89OvgoU" alt="Actions SemVer Checker Action" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's a sample workflow that will flag any versioning issues:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check SemVer&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;check-semver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;concurrency&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.workflow&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
      &lt;span class="na"&gt;cancel-in-progress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jessehouwing/actions-semver-checker@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;warn-minor-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion​
&lt;/h2&gt;

&lt;p&gt;There are a lot of things an action author can do to ensure the security of their own actions. Apart from all of these repository settings, it's of course important to create an action that's secure by itself. The GitHub Security Lab Blog has written a number of articles on Action Security that I whole heartedly recommend:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://securitylab.github.com/research/github-actions-preventing-pwn-requests/" rel="noopener noreferrer"&gt;Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://securitylab.github.com/research/github-actions-untrusted-input/" rel="noopener noreferrer"&gt;Keeping your GitHub Actions and workflows secure Part 2: Untrusted input&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://securitylab.github.com/research/github-actions-building-blocks/" rel="noopener noreferrer"&gt;Keeping your GitHub Actions and workflows secure Part 3: How to trust your building blocks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's build a more secure Actions ecosystem together!&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>github</category>
      <category>security</category>
      <category>supplychainsecurity</category>
    </item>
    <item>
      <title>Definitive solution for log4shell in Azure DevOps Server Search</title>
      <dc:creator>Jesse Houwing</dc:creator>
      <pubDate>Fri, 25 Nov 2022 09:57:52 +0000</pubDate>
      <link>https://dev.to/xebia/definitive-solution-for-log4shell-in-azure-devops-server-search-4opb</link>
      <guid>https://dev.to/xebia/definitive-solution-for-log4shell-in-azure-devops-server-search-4opb</guid>
      <description>&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%2F2gy6fw2yicvzyibwykt3.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%2F2gy6fw2yicvzyibwykt3.jpg" alt="Definitive solution for log4shell in Azure DevOps Server Search" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A version of Azure DevOps Server with a reasonably recent, secure, and supported version of Elastic Search is coming soon.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/xpirit/azure-devops-2020-and-2019-and-2018-patch-for-log4j-vulnerability-596i"&gt;Azure DevOps 2020 and 2019 (and 2018) patch for log4j vulnerability&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Azure DevOps can be configured with advanced Code Search. That feature relies on Elastic Search. Depending on the age of your server, JVM version and Elastic Search version this may result in your setup being vulnerable to CVE-2021-44228.&lt;/p&gt;

&lt;h1&gt;
  
  
  Azure DevOps Server 2022
&lt;/h1&gt;

&lt;p&gt;Microsoft finally will be releasing Azure DevOps Server 2022, which ships with Elastic Search 7.17.5:&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%2Fhyl4qbnq9g06398231kk.png" 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%2Fhyl4qbnq9g06398231kk.png" alt="Definitive solution for log4shell in Azure DevOps Server Search" width="772" height="412"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Elastic Search 7.17.5 that ships with Azure DevOps Server 2022 RTW&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This version no longer ships with patched jar files, but finally ships with the version of log4j that should be secure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrading
&lt;/h2&gt;

&lt;p&gt;You won't be able to use this version of Elastic Search with an older version of Azure DevOps Server, the way to go is to perform the upgrade to 2022.&lt;/p&gt;

&lt;h2&gt;
  
  
  Need help?
&lt;/h2&gt;

&lt;p&gt;In case you need help to prepare or perform an upgrade of your aging Team Foundation Server or Azure DevOps Server installation, don't hesitate to reach out.&lt;/p&gt;

</description>
      <category>azuredevopsserver</category>
      <category>security</category>
      <category>log4shell</category>
      <category>log4j</category>
    </item>
    <item>
      <title>What's GitHub's new require approval of the most recent push policy all about?</title>
      <dc:creator>Jesse Houwing</dc:creator>
      <pubDate>Wed, 23 Nov 2022 12:38:21 +0000</pubDate>
      <link>https://dev.to/xebia/whats-githubs-new-require-approval-of-the-most-recent-push-policy-all-about-4pij</link>
      <guid>https://dev.to/xebia/whats-githubs-new-require-approval-of-the-most-recent-push-policy-all-about-4pij</guid>
      <description>&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%2Fksvtw0n81v1jkvoz9cn7.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%2Fksvtw0n81v1jkvoz9cn7.jpg" alt="What's GitHub's new require approval of the most recent push policy all about?" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It was introduced with the express intent to prevent &lt;a href="https://www.legitsecurity.com/blog/bypassing-github-required-reviewers-to-submit-malicious-code" rel="noopener noreferrer"&gt;someone responding to a code review request from sneaking in changes and approving them themselves or using the already supplied approval from another reviewer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The security research that explores these topics has not been broadly published, but there are some &lt;a href="https://medium.com/boostsecurity/slsa-dip-source-of-the-problem-a1dac46a976" rel="noopener noreferrer"&gt;great discussions with recommendations on how to secure your branches&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With this new policy enabled, when a reviewer applies some suggestions to the code, they can't approve and merge the code without finding another person to review their changes.&lt;/p&gt;

&lt;p&gt;Excerpts from the article, red team, emphasis mine:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;— Modify code after review  &lt;/p&gt;

&lt;p&gt;After the attacker submits a valid and good code change that is approved, the attacker abuses their existing approval to make further changes that include bad code while retaining the stale approval.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Another scenario is that the attacker could first be a good samaritan and approve the code of a fellow developer, let’s assume it’s a good code change, but it doesn’t matter. What matters is that once they have approved that pull request, they could abuse their own write access, add bad code and self-approve their own code change.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And the protections, blue team, emphasis mine:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Require a pull request before merging  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Require approvals
&lt;/li&gt;
&lt;li&gt;Dismiss stale pull request approvals when new commits are pushed
&lt;/li&gt;
&lt;li&gt;Require review from Code Owners
&lt;/li&gt;
&lt;li&gt;Allow specified actors to bypass required pull requests (avoid unless you absolutely need to)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Require approval of the most recent push (this is a new setting, as of October 2022, and is really great mitigation for some of our attack scenarios)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Require status checks to pass before merging (it you have some form of CI with tests, linters, SAST, it would be great to enforce those)
&lt;/li&gt;
&lt;li&gt;Require signed commits (this is great for end-to-end accountability)
&lt;/li&gt;
&lt;li&gt;Enforce Branch Protection for administrator (i.e. “Do not allow bypassing the above settings”)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Recommended mitigations, emphasis mine:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;— Modify code after review  &lt;/p&gt;

&lt;p&gt;Attacker submits good code, gets approval, then submits bad code &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The mitigation is to set your Branch Protection to “Dismiss stale pull request approvals when new commits are pushed”. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;_ &lt;strong&gt;Attacker approves someone else’s good code, then submits bad code and self-approves changes&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The mitigation is to set your Branch Protection to “Require approval of the most recent push”.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

</description>
      <category>github</category>
      <category>security</category>
    </item>
    <item>
      <title>Issuing workflow commands from the Windows shell in GitHub Actions</title>
      <dc:creator>Jesse Houwing</dc:creator>
      <pubDate>Tue, 15 Nov 2022 17:54:12 +0000</pubDate>
      <link>https://dev.to/xebia/issuing-workflow-commands-from-the-windows-shell-in-github-actions-3gm4</link>
      <guid>https://dev.to/xebia/issuing-workflow-commands-from-the-windows-shell-in-github-actions-3gm4</guid>
      <description>&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%2F89nxalz4ezm39cwccj2b.png" 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%2F89nxalz4ezm39cwccj2b.png" alt="Issuing workflow commands from the Windows shell in GitHub Actions" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's a little-known fact that the default shell in for GitHub Actions is different depending on the operating system on which you run. And that the syntax to set a variable, for example, differs too.&lt;/p&gt;

&lt;p&gt;The docs explain the syntax for Bash and PowerShell: &lt;br&gt;
&lt;a href="https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions" rel="noopener noreferrer"&gt;Workflow commands for GitHub Actions - GitHub Docs&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below is an example of the different syntax required to set an output variable in each of the most common shells:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  windows:
    runs-on: windows-latest
    steps:
    # Runs on PowerShell Core
    - name: Set an output variable on Windows
      run: |
        echo foo=bar &amp;gt;&amp;gt; $env:GITHUB_OUTPUT

  linux:
    runs-on: ubuntu-latest
    steps:
    # Runs on Bash
    - name: Set an output variable on Linux
      run: |
        echo foo=bar &amp;gt;&amp;gt; $GITHUB_OUTPUT

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

&lt;/div&gt;



&lt;p&gt;When you always target the same OS, it won't matter much, but if you have multi-platform jobs, matrix jobs, reusable templates, and composite actions, it pays to be explicit. That way your bash script won't suddenly be executed by PowerShell or vice versa.&lt;/p&gt;

&lt;p&gt;You aren't limited to &lt;code&gt;pwsh&lt;/code&gt; on windows or &lt;code&gt;bash&lt;/code&gt; on linux and mac either. As long as they are installed on the Runner, you can run either on each OS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  windows:
    runs-on: windows-latest
    steps:
    # Runs on Bash
    - name: Set an output variable on Windows
      run: |
        echo foo=bar &amp;gt;&amp;gt; $GITHUB_OUTPUT
      shell: bash
    - name: Set an output variable on Windows
      run: |
        echo foo=bar &amp;gt;&amp;gt; $env:GITHUB_OUTPUT
      shell: pwsh
    - name: Set an output variable on Windows
      # Requires explicitly setting the output encoding
      run: |
        "foo=bar" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
      shell: powershell


  linux:
    runs-on: ubuntu-latest
    steps:
    # Runs on Bash
    - name: Set an output variable on Linux
      run: |
        echo foo=bar &amp;gt;&amp;gt; $GITHUB_OUTPUT
    - name: Set an output variable on Linux
      run: |
        echo foo=bar &amp;gt;&amp;gt; $env:GITHUB_OUTPUT
      shell: pwsh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Today someone asked what the correct syntax would be to do this on the &lt;code&gt;shell: cmd&lt;/code&gt; old Windows Command Shell. I couldn't find that in the docs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To be honest, since I wrote half of that doc, I was certain I didn't add that information...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But after some experimentation I found out you need to do the same things you'd do for the old PowerShell. Set the encoding to utf-8 and use the correct environment variable syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  windows:
    runs-on: windows-latest
    steps:
    - shell: cmd
      run: |
        @chcp 65001&amp;gt;nul
        echo foo=bar &amp;gt;&amp;gt; %GITHUB_OUTPUT%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://stackoverflow.com/a/74444094/736079" rel="noopener noreferrer"&gt;First published here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>github</category>
      <category>windowsserver</category>
    </item>
    <item>
      <title>Update Ghost blogs and pages with PowerShell</title>
      <dc:creator>Jesse Houwing</dc:creator>
      <pubDate>Fri, 30 Sep 2022 08:17:34 +0000</pubDate>
      <link>https://dev.to/xebia/update-ghost-blogs-and-pages-with-powershell-49i5</link>
      <guid>https://dev.to/xebia/update-ghost-blogs-and-pages-with-powershell-49i5</guid>
      <description>&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%2Fi5l21kkobs4aa6ezx7vg.webp" 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%2Fi5l21kkobs4aa6ezx7vg.webp" alt="Update Ghost blogs and pages with PowerShell" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ghost.org/docs/admin-api/#token-authentication" rel="noopener noreferrer"&gt;The samples provided by Ghost are in JavaScript, Curl and Python&lt;/a&gt;, all languages I'm not fluent in, so I set out to do the same from PowerShell or C#.&lt;/p&gt;

&lt;p&gt;The hardest part turned out to be the code to create the correct JWT token to authenticate against Ghost. In their admin panel they provide a set of tokens, but it turns out you can't just use these tokens as-is.&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%2Fy9qgvds7ndavq2uhcogw.png" 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%2Fy9qgvds7ndavq2uhcogw.png" alt="Update Ghost blogs and pages with PowerShell" width="800" height="311"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;API Key provided by Ghost&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The API key essentially makes up 2 parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Key Identifier, that's the part up to the &lt;code&gt;:&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The Secret, that's the part after the &lt;code&gt;:&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In order to use this key, we first have to split it into its two parts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$parts = $adminApiKey -split ":"
$id = $parts[0]
$secret = $parts[1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then need to construct a JWT token from this key. I relied on &lt;a href="https://github.com/SP3269/posh-jwt" rel="noopener noreferrer"&gt;the Posh-JWT package&lt;/a&gt; for that part:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Install-Module -Name JWT -force

$key = [Convert]::FromHexString($secret) # only works in PowerShell Core

$jwttoken = New-Jwt `
  -Header (
    @{
      "alg" = "HS256"
      "kid" = $id
      "typ" = "JWT"
    } | ConvertTo-Json
  ) `
  -PayloadJson (
    @{
      "exp" = ([DateTimeOffset](Get-Date).AddMinutes(2)).ToUnixTimeSeconds()
      "iat" = ([DateTimeOffset](Get-Date)).ToUnixTimeSeconds()
      "aud" = "/admin/"
    } | ConvertTo-Json) 
  -Secret $key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this token, you can then invoke the Ghost API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$headers = @{
  Authorization = "Ghost $jwttoken"
  "Content-Type" = "application/json"
}

$baseUri = "https://scrumbug.ghost.io/ghost/api"

$result = Invoke-RestMethod `
  -Uri "$baseUri/admin/pages/" `
  -Method GET `
  -Headers $headers     
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As I said, I used this code to automatically sync my Scrum.org classes to this blog. You can find the &lt;a href="https://github.com/jessehouwing/jessehouwing/blob/master/.github/actions/update-scrum-classes-on-ghost/action.yml" rel="noopener noreferrer"&gt;(private) Ghost update GitHub Action here&lt;/a&gt;. To keep my secrets secure I added a couple of extra lines of code to register my secrets with the runner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write-Output "::add-mask::$id"
...
Write-Output "::add-mask::$secret"
...
Write-Output "::add-mask::$key"
...
Write-Output "::add-mask::$jwttoken"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to &lt;a href="https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#masking-a-value-in-log" rel="noopener noreferrer"&gt;always register your secrets every time they change their shape or representation to prevent your secrets from leaking into the GitHub Action logs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;End result? My classes are automatically updated 🎉:&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%2F0hilae1j27qq3qxvgsor.png" 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%2F0hilae1j27qq3qxvgsor.png" alt="Update Ghost blogs and pages with PowerShell" width="800" height="311"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Github actions workflow runs successfully&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ghost</category>
      <category>githubactions</category>
      <category>github</category>
      <category>powershell</category>
    </item>
  </channel>
</rss>
