kitchen-azurerm
A Test Kitchen driver for Microsoft Azure.
Test Kitchen builds a throwaway machine, converges your configuration code on it, runs your tests, and destroys it. This driver makes that throwaway machine an Azure virtual machine, so you can test against the same platform you deploy to. It talks to the Azure Resource Manager REST API directly and depends only on the Ruby standard library to do so.
Tested on Windows, macOS, and Linux. If you hit a problem on your platform, please raise an issue.
This documentation uses Cinc Workstation and the
cinccommands throughout. Everything here works identically with Chef Workstation — see Using with Chef.
Contents
- Requirements
- Installation
- Quick start
- Authentication
- Configuration reference
- Other commands
- Common setups
- Finding an image URN
- Troubleshooting
- Using with Chef
- Contributing
- Author
- License and Copyright
Requirements
- Ruby 3.1 or newer (already satisfied if you use Cinc Workstation)
- An active Azure subscription — you can start for free or use an MSDN subscription
- A way to authenticate to it, with rights to create resources. A service principal with the Contributor role is the usual choice; see Authentication for the alternatives.
The Azure CLI is not required at run time, but the quick start uses it to create the service principal and to look up images.
Installation
This driver ships with Cinc Workstation, which is the simplest way to get Test Kitchen and its plugins in one package. It also ships with Chef Workstation.
To install it yourself, add it to your Gemfile:
gem "kitchen-azurerm"then bundle install. Or install the gem directly:
gem install kitchen-azurermQuick start
1. Create a service principal
The driver needs an identity with Contributor rights on the subscription you
want to deploy into. After az login:
az ad sp create-for-rbac --name "kitchen-azurerm" \
--role "Contributor" \
--scopes "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"which prints:
{
"appId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"displayName": "kitchen-azurerm",
"password": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"tenant": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}Save the password now — Azure will not show it again. You need four
values: the subscription ID, appId (the client ID), password (the client
secret), and tenant.
Organizational (Entra ID) account and password authentication is no longer supported. If you are setting this up for CI, prefer workload identity federation and skip the secret entirely.
2. Store the credentials
Create ~/.azure/credentials, with one section per subscription ID. Save it
as UTF-8.
[your-azure-subscription-id-here]
client_id = "your-azure-client-id-here"
client_secret = "your-client-secret-here"
tenant_id = "your-azure-tenant-id-here"Or use environment variables, which take precedence over the file but cannot describe more than one subscription:
export AZURE_CLIENT_ID="your-azure-client-id-here"
export AZURE_CLIENT_SECRET="your-client-secret-here"
export AZURE_TENANT_ID="your-azure-tenant-id-here"3. Write your kitchen.yml
---
driver:
name: azurerm
subscription_id: <%= ENV["AZURE_SUBSCRIPTION_ID"] %>
location: westeurope
machine_size: Standard_D2s_v3
transport:
ssh_key: ~/.ssh/id_kitchen-azurerm
provisioner:
name: cinc_infra
verifier:
name: cinc_auditor
platforms:
- name: ubuntu-22.04
suites:
- name: defaultIf the SSH key does not exist at the path you give, Test Kitchen creates it.
When ssh_key is set, Test Kitchen uses it in preference to any password.
4. Run it
cinc kitchen testOr step through it:
cinc kitchen create # deploy the resource group and VM
cinc kitchen converge # apply your configuration
cinc kitchen verify # run your tests
cinc kitchen destroy # delete the resource groupcinc kitchen list shows what is configured and what state it is in:
Instance Driver Provisioner Verifier Transport Last Action Last Error
default-ubuntu-2204 Azurerm CincInfra CincAuditor Ssh <Not Created> <None>
Authentication
The driver picks an authentication method from whatever resolves, in this order:
| Method | Configure with | Use when |
|---|---|---|
| Workload identity federation |
AZURE_FEDERATED_TOKEN_FILE + AZURE_CLIENT_ID + AZURE_TENANT_ID
|
CI — GitHub Actions, GitLab, Azure DevOps, AKS. No secret to store. |
| Service principal |
AZURE_CLIENT_ID + AZURE_CLIENT_SECRET + AZURE_TENANT_ID, or the credentials file |
A long-lived secret you manage yourself. |
| Managed identity |
AZURE_CLIENT_ID for a user-assigned identity, AZURE_USE_MSI=1 for a system-assigned one |
Running on an Azure VM or in AKS. |
| Azure CLI | az login |
Local development. |
Values come from the environment first, then the matching subscription section of the credentials file.
Workload identity federation
This is the method to prefer in CI. Rather than storing a secret, your CI platform issues a short-lived signed assertion which Azure exchanges for an access token, so there is no credential in your repository or your CI settings to leak, rotate, or accidentally print.
Set up a federated credential trusting your repository, then in GitHub Actions:
permissions:
id-token: write
contents: read
steps:
- uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- run: bundle exec kitchen testazure/login writes the assertion to a file and exports
AZURE_FEDERATED_TOKEN_FILE, AZURE_CLIENT_ID and AZURE_TENANT_ID, which is
all this driver needs. Nothing in kitchen.yml changes.
The assertion is re-read from disk on every token request, so a long
kitchen test run keeps working when the platform rotates it.
AZURE_AUTHORITY_HOST is honoured if your platform sets it, as AKS does.
Managed identity
On an Azure VM or in AKS, set AZURE_CLIENT_ID to the user-assigned identity's
client ID, or AZURE_USE_MSI=1 to use the system-assigned identity. Tokens come
from the instance metadata service; no tenant is required.
Configuration reference
All options below are set under the driver: key in kitchen.yml, or per platform under platforms[].driver:.
Required
| Option | Default | Description |
|---|---|---|
subscription_id |
from credentials file / AZURE_SUBSCRIPTION_ID
|
Azure subscription to deploy into. |
location |
none | Azure region, e.g. westeurope. Required. |
machine_size |
none | VM size, e.g. Standard_D2s_v3. Required. |
Image
Set one of image_urn or image_id.
| Option | Default | Description |
|---|---|---|
image_urn |
Canonical:0001-com-ubuntu-server-jammy:22_04-lts-gen2:latest |
Marketplace image, as Publisher:Offer:Sku:Version. See Finding an image URN. |
image_id |
"" |
Resource ID of a private managed image or an Azure Compute Gallery image version. |
plan |
unset | Purchase plan for a Marketplace image that requires one. A hash accepting name, product, publisher, and promotion_code. |
Virtual machine
| Option | Default | Description |
|---|---|---|
vm_name |
nil |
Explicit VM name. Generated from vm_prefix if unset. |
vm_prefix |
"tk-" |
Prefix for the generated VM name. |
vm_tags |
{} |
Tags applied to the VM. |
username |
"azure" |
Admin username created on the VM. |
password |
generated | Admin password. A random one is generated if unset. |
custom_data |
"" |
Custom data passed to the VM, as a string or a path to a file. |
use_fqdn_hostname |
false |
Connect using the FQDN rather than the IP address. |
store_deployment_credentials_in_state |
true |
Persist the generated credentials in the Test Kitchen state file. |
Disks
| Option | Default | Description |
|---|---|---|
use_ephemeral_osdisk |
false |
Use an ephemeral OS disk, which is faster and cheaper but lost on deallocation. |
os_disk_size_gb |
image default | Size of the OS disk in GB. Must be at least the image's own size. |
storage_account_type |
"StandardSSD_LRS" |
Managed disk type, e.g. StandardSSD_LRS, Premium_LRS. |
data_disks |
nil |
Array of data disks to attach, each a hash with lun and disk_size_gb. |
format_data_disks |
false |
Format and mount attached data disks. Windows only. |
format_data_disks_powershell_script |
false |
Custom PowerShell script used to format the data disks. |
All deployments use managed disks. Azure retired unmanaged disks on 31 March 2026.
Networking
| Option | Default | Description |
|---|---|---|
vnet_id |
"" |
Resource ID of an existing virtual network. Leave unset to create one. |
subnet_id |
"" |
Subnet to attach to: either its name within vnet_id, or its full resource ID. |
nic_name |
"" |
Name of an existing network interface to attach. |
public_ip |
false |
Assign a public IP address. Required unless you reach the VM over ExpressRoute or a VPN. |
public_ip_sku |
"Standard" |
Public IP SKU. Azure retired the Basic SKU on 30 September 2025. |
nsg_id |
"" |
Resource ID of an existing network security group to attach to the network interface. When unset, one is created for you. |
open_ports |
[] |
Extra inbound TCP ports to open, on top of the transport's own port. |
Standard SKU public IPs are closed to inbound traffic unless a network security
group allows it. When the driver creates a public IP and you have not supplied
nsg_id, it also creates a security group allowing inbound TCP on the port your
transport uses - 22 for SSH, 5985 and 5986 for WinRM - plus anything in
open_ports. Those rules allow any source address, matching the connectivity a
Basic SKU public IP used to provide. To restrict the source, create your own
security group and pass it as nsg_id.
Resource group
| Option | Default | Description |
|---|---|---|
azure_resource_group_name |
derived | Name of the resource group created for the run. |
azure_resource_group_prefix |
"kitchen-" |
Prefix for the generated resource group name. |
azure_resource_group_suffix |
"" |
Suffix for the generated resource group name. |
explicit_resource_group_name |
nil |
Deploy into an existing resource group instead of creating one. |
resource_group_tags |
{} |
Tags applied to a resource group the driver creates. |
destroy_explicit_resource_group |
true |
Delete the explicit resource group on destroy. Set to false when deploying into a shared group. |
destroy_explicit_resource_group_tags |
true |
Remove the tags the driver added to an explicit resource group on destroy. |
destroy_resource_group_contents |
false |
Delete the resource group's contents rather than the group itself. |
Identity
| Option | Default | Description |
|---|---|---|
system_assigned_identity |
false |
Enable a system-assigned managed identity on the VM. |
user_assigned_identities |
[] |
Array of user-assigned managed identity resource IDs. |
Key Vault
| Option | Default | Description |
|---|---|---|
secret_url |
"" |
URL of a Key Vault certificate to install on the VM. |
vault_name |
"" |
Name of the Key Vault holding it. |
vault_resource_group |
"" |
Resource group containing the vault. |
ARM templates
| Option | Default | Description |
|---|---|---|
pre_deployment_template |
"" |
Path to an ARM template deployed before the VM. |
pre_deployment_parameters |
{} |
Parameters for the pre-deployment template. |
post_deployment_template |
"" |
Path to an ARM template deployed after the VM. |
post_deployment_parameters |
{} |
Parameters for the post-deployment template. |
Environment and behaviour
| Option | Default | Description |
|---|---|---|
azure_environment |
"Azure" |
Cloud to target: Azure, AzureUSGovernment, AzureChina, AzureGermanCloud. See Government and sovereign clouds. |
boot_diagnostics_enabled |
true |
Enable managed boot diagnostics on the VM. |
winrm_powershell_script |
false |
Custom PowerShell script used to configure WinRM. Windows only. |
deployment_sleep |
10 |
Seconds to wait between polls of the deployment status. |
azure_api_retries |
5 |
Number of times to retry a failed Azure API call. |
Retired settings
These settings are still accepted so that an existing kitchen.yml keeps
loading, but Azure retirements have made them inoperable. The driver logs a
warning and ignores them.
| Option | Retired because |
|---|---|
use_managed_disks |
Azure retired unmanaged disks on 31 March 2026. Every deployment now uses managed disks. |
image_url |
Deploying from a VHD URL required unmanaged disks. Use image_id with a managed image or an Azure Compute Gallery image instead. |
os_type |
Only ever applied to image_url deployments. |
existing_storage_account_blob_url |
OS disks are no longer placed in a storage account you supply. |
existing_storage_account_container |
As above. |
Other commands
kitchen doctor
Checks the configuration and the credentials up front, rather than letting a deployment discover the problem for you:
cinc kitchen doctor default-ubuntu-2204A failed create is usually one of two things — a required setting nobody filled
in, or credentials that do not work. Both otherwise surface as an Azure error
partway through kitchen create, once the resource group already exists.
It reports every problem it finds rather than stopping at the first, and exits non-zero when there is one:
-----> The doctor is in
>>>>>> kitchen-azurerm: location is not set. It has no default: give it the Azure region to deploy into, e.g. eastus.
>>>>>> kitchen-azurerm: machine_size is not set. It has no default: give it the VM size to deploy, e.g. Standard_D2s_v3.
Once subscription_id, location, and machine_size are all set, it goes on
to read the subscription itself. That proves the credentials work and that
they reach the subscription you configured — a resource group check cannot,
because Azure answers 404 both for a subscription that does not exist and for
one that merely has no such group:
-----> The doctor is in
>>>>>> kitchen-azurerm: Azure rejected the request (AuthorizationFailed: The client does not have authorization to perform action 'Microsoft.Resources/subscriptions/read' over scope '/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'). Check the credentials, and that they can reach subscription xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
Test Kitchen doctors only the first instance unless you name one or pass
--all. Since these checks are about configuration and credentials rather than
any particular instance, the first one is normally all you need.
kitchen list --live
Asks Azure what power state each virtual machine is actually in, rather than reporting only the last action Test Kitchen took:
cinc kitchen list --liveInstance Driver Provisioner Verifier Transport Last Action Last Error Live Status
default-ubuntu-2204 Azurerm CincInfra CincAuditor Ssh Converged <None> deallocated
The live status is Azure's own power state — running, starting, stopping,
stopped, deallocating, or deallocated — plus not_created when the state
file names no virtual machine, and unknown when Azure could not be reached,
no longer has the machine, or answered with a state this driver does not
recognise. In the last case the message carries Azure's own wording.
This is how a deallocated or hand-deleted VM shows up: Test Kitchen still
believes the instance is Converged, because from its point of view nothing has
happened since. It is also the quickest way to find instances that are still
running up a bill.
Unlike kitchen create and kitchen destroy, this does not retry: it sits
behind an interactive command, and waiting out the retry budget on every
unreachable instance would be worse than saying so promptly.
Common setups
Each of these shows only the parts that matter — combine them with the quick
start's kitchen.yml as needed. Any driver: setting can be given at the top
level or per platform under platforms[].driver:.
Windows over WinRM
The VM enables itself for remote access at deployment time. This example also uses an ephemeral OS disk, which is faster and cheaper but lost when the VM is deallocated, and tags both the VM and its resource group.
---
driver:
name: azurerm
subscription_id: <%= ENV["AZURE_SUBSCRIPTION_ID"] %>
location: westeurope
machine_size: Standard_DS2_v2
provisioner:
name: cinc_infra
verifier:
name: cinc_auditor
platforms:
- name: windows-2022
driver:
image_urn: MicrosoftWindowsServer:WindowsServer:2022-Datacenter-smalldisk:latest
use_ephemeral_osdisk: true
resource_group_tags:
project: My Cool Project
contact: me@somewhere.com
vm_tags:
my_tag: its value
another_tag: its awesome value
transport:
name: winrm
suites:
- name: defaultRunning instances concurrently
Each machine is created in its own Azure resource group, so instances share no lifecycle and can be built in parallel:
cinc kitchen test --concurrency 4Any failure fails the whole run, though resources already being created will finish being created.
Deploying into an existing virtual network
Set vnet_id and subnet_id to place the VM on a network that already exists,
possibly in a different resource group. This is the usual setup when you reach
the VM over ExpressRoute or a VPN rather than a public address.
platforms:
- name: ubuntu-22.04
driver:
image_urn: Canonical:0001-com-ubuntu-server-jammy:22_04-lts-gen2:latest
vnet_id: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/my-infrastructure/providers/Microsoft.Network/virtualNetworks/my-vnet
subnet_id: my-subnetsubnet_id also accepts a full subnet resource ID, which is useful when the
subnet lives somewhere other than vnet_id:
subnet_id: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/my-infrastructure/providers/Microsoft.Network/virtualNetworks/my-vnet/subnets/my-subnetNo public IP address is assigned unless you also set public_ip: true. When
the subnet sits behind a NAT gateway, or otherwise needs a Standard SKU
address, add:
public_ip: true
public_ip_sku: StandardStandard SKU public IPs are closed to inbound traffic unless a network security group allows it — see the note under Networking.
Using a private image
Set image_id to the resource ID of a managed image or an Azure Compute
Gallery image version, in place of image_urn. The image must already exist.
platforms:
- name: my-custom-image
driver:
image_id: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/my-images/providers/Microsoft.Compute/images/my-imageEverything created for the run, including the OS disk, is removed on
kitchen destroy.
Deploying from a VHD URL in a storage account is no longer supported. Azure retired unmanaged disks on 31 March 2026 — see Retired settings.
Custom data and a larger OS disk
custom_data takes either a string or a path to a file, and os_disk_size_gb
grows the OS disk beyond the image's own size.
platforms:
- name: ubuntu-22.04
driver:
image_urn: Canonical:0001-com-ubuntu-server-jammy:22_04-lts-gen2:latest
custom_data: cloud-init.txt
os_disk_size_gb: 128Custom data is how WinRM gets enabled on non-Nano Windows images, so setting
custom_datayourself is not supported when using the WinRM transport.
Attaching data disks
Each entry needs a lun and a disk_size_gb:
platforms:
- name: windows-2022
driver:
image_urn: MicrosoftWindowsServer:WindowsServer:2022-Datacenter:latest
data_disks:
- lun: 0
disk_size_gb: 128
- lun: 1
disk_size_gb: 128
- lun: 2
disk_size_gb: 128
format_data_disks: trueformat_data_disks runs a PowerShell script at first boot to initialize and
format the disks as NTFS. It has no effect on Linux.
Managed identities
Any combination of system-assigned and user-assigned identities can be enabled, and multiple user-assigned identities can be supplied. See the managed identities documentation.
platforms:
- name: ubuntu-22.04
driver:
image_urn: Canonical:0001-com-ubuntu-server-jammy:22_04-lts-gen2:latest
system_assigned_identity: true
user_assigned_identities:
- /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourcegroups/test-kitchen-user/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test-kitchen-userInstalling a Key Vault certificate
driver:
name: azurerm
subscription_id: <%= ENV["AZURE_SUBSCRIPTION_ID"] %>
location: centralus
machine_size: Standard_D2s_v3
secret_url: https://YOUR-VAULT.vault.azure.net/secrets/YOUR-SECRET/YOUR-VERSION
vault_name: YOUR-VAULT-NAME
vault_resource_group: YOUR-VAULT-RESOURCE-GROUP
transport:
name: winrm
elevated: true
provisioner:
name: cinc_infra
platforms:
- name: windows-2022
driver:
image_urn: MicrosoftWindowsServer:WindowsServer:2022-Datacenter:latest
suites:
- name: defaultARM templates before and after the VM
pre_deployment_template runs an ARM template before the system under test is
created; post_deployment_template runs one after. Both deploy into the same
resource group as the VM, so both are torn down by kitchen destroy.
driver:
name: azurerm
subscription_id: <%= ENV["AZURE_SUBSCRIPTION_ID"] %>
location: westeurope
machine_size: Standard_D2s_v3
pre_deployment_template: predeploy.json
pre_deployment_parameters:
test_parameter: This is a test.
post_deployment_template: postdeploy.json
post_deployment_parameters:
test_parameter: This is a test.A minimal predeploy.json:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"test_parameter": {
"type": "string",
"defaultValue": ""
}
},
"variables": {},
"resources": [],
"outputs": {
"parameter testing": {
"type": "string",
"value": "[parameters('test_parameter')]"
}
}
}A post-deployment template runs against the VM that was just created, so it can
reference it — for example to attach an extension. Use the vmName the driver
reports, and declare the dependency:
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', parameters('vmName'))]"
]Government and sovereign clouds
Set azure_environment to target a cloud other than global Azure. Valid values
are Azure, AzureUSGovernment, AzureChina, and AzureGermanCloud.
---
driver:
name: azurerm
subscription_id: <%= ENV["AZURE_SUBSCRIPTION_ID"] %>
azure_environment: AzureUSGovernment
location: usgoviowa
machine_size: Standard_D2_v2
provisioner:
name: cinc_infra
verifier:
name: cinc_auditor
platforms:
- name: ubuntu-22.04
driver:
image_urn: Canonical:0001-com-ubuntu-server-jammy:22_04-lts-gen2:latest
transport:
ssh_key: ~/.ssh/id_kitchen-azurerm
suites:
- name: defaultFinding an image URN
An image_urn has four parts — Publisher:Offer:Sku:Version. All four must be
given, though the last can be latest to always take the newest version.
List the offers a publisher has in your region:
az vm image list --location westeurope --publisher Canonical \
--all --output tableArchitecture Offer Publisher Sku Version Urn
------------ ------------------------------- --------- ---------------- -------------- ----------------------------------------------------------------------------
x64 0001-com-ubuntu-server-jammy Canonical 22_04-lts-gen2 22.04.202401161 Canonical:0001-com-ubuntu-server-jammy:22_04-lts-gen2:22.04.202401161
x64 0001-com-ubuntu-server-noble Canonical 24_04-lts-gen2 24.04.202404230 Canonical:0001-com-ubuntu-server-noble:24_04-lts-gen2:24.04.202404230
Take the Urn column and replace the version with latest if you want the
newest each run. Drop --all for a much shorter list of current images, and
add --offer to narrow further.
Troubleshooting
kitchen create fails immediately with an authentication error.
Run cinc kitchen doctor first — it reads the subscription
with whatever credentials resolved and reports exactly what Azure said. Then
check which method is actually being picked — see Authentication.
The environment wins over ~/.azure/credentials, so a stale AZURE_CLIENT_ID
exported in your shell will silently override the file. Confirm the service
principal still has Contributor on the subscription in subscription_id.
The credentials file is ignored. It must be saved as UTF-8, and the section header is the bare subscription ID in square brackets, with no quotes.
The deployment succeeds but Test Kitchen cannot connect.
Almost always the network. If you set public_ip: false, you need
ExpressRoute, a VPN, or a jump host to reach the VM at all. If you have a
public IP, remember Standard SKU addresses are closed by default: the driver
creates a security group opening your transport's port only when it creates the
public IP and you have not supplied nsg_id. Supply open_ports for anything
extra.
The requested size for resource is currently not available in location.
The machine_size is not offered in that region, or your subscription has no
quota for it. az vm list-skus --location westeurope --size Standard_D --output table
shows what is available.
A Key Vault certificate is not installed and no error is raised.
Check the option name. It is vault_resource_group — vault_group_name is not
a real setting and is silently ignored.
An option in my kitchen.yml has no effect.
Check it against Retired settings. Those are still accepted
so old configuration keeps loading, but the driver logs a warning and ignores
them.
Resources are left behind after a failed run.
A kitchen test that fails partway can leave the resource group in place.
cinc kitchen destroy removes it. If you deployed into an existing group with
explicit_resource_group_name and destroy_explicit_resource_group: false,
nothing is deleted by design — clean up in the portal.
Using with Chef
This driver is not tied to Cinc. It provisions Azure resources and does not
itself install either distribution — that is the provisioner's job. The
examples above use Cinc Workstation and the cinc_infra provisioner; with
Chef Workstation run
kitchen instead of cinc kitchen, and substitute the plugin names:
| Cinc | Chef |
|---|---|
cinc kitchen test |
kitchen test |
cinc_infra provisioner |
chef_infra provisioner |
cinc_auditor verifier |
inspec verifier |
provisioner:
name: chef_infra
verifier:
name: inspecNo driver configuration changes are needed.
Contributing
Contributions to the project are welcome via submitting Pull Requests. See CONTRIBUTING.md for development setup, how to run the tests, and the release process.
Author
Stuart Preston
License and Copyright
Copyright 2015-2021, Chef Software, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.