microsoft / PSRule

Validate infrastructure as code (IaC) and objects using PowerShell rules.
https://microsoft.github.io/PSRule/v2/
MIT License
385 stars 49 forks source link

Add a cmdlet to export a baseline #622

Closed BernieWhite closed 2 years ago

BernieWhite commented 3 years ago

Existing baselines shipped in a module can't be edited directly, a new baseline needs to be created and used separately.

It would be nice to have a cmdlet to export a baseline to a YAML file.

For example:

Export-PSRuleBaseline -Module 'PSRule.Rules.Azure' -Baseline 'Azure.GA_2020_12' -OutputPath 'out/';
ArmaanMcleod commented 2 years ago

@BernieWhite Happy to help with this one.

I can probably create a ExportPipelineBuilder class that would encapsulate the export functionality for the pipeline.

I guess the same could also be accomplished with Get-PSRuleBaseline -OutputFormat Yaml | Out-File -Path <output file> with the recent YAML output format capability.

BernieWhite commented 2 years ago

@ArmaanMcleod Awesome. Good idea. Yes, we should be able to build on the work you already did with the YAML output for baselines.

When writing a file ideally, we should observe Output.Encoding as well as -WhatIf. The general behaviour of PSRule is to create subdirectories if they do not exist along the output path.

Another thought that ideally, I'd like to meet although may create some challenges above the Get-PSRuleBaseline -OutputFormat Yaml implementation:

If it is easier to update Get-PSRuleBaseline -OutputFormat Yaml first for these adjustments, then please do.

Reach out if you have any questions on this.

ArmaanMcleod commented 2 years ago

Thanks @BernieWhite. I could probably work on outputting synopsis as a comment and putting --- between baselines for Get-PSRuleBaseline -OutputFormat Yaml first.

With this in mind it might be worth making a Yaml converter for the Baseline.

Do you think there is an easier way?

BernieWhite commented 2 years ago

@ArmaanMcleod I haven't investigated it enough but I think you will need to implement a custom ISerializer.

This is the implementation to read multiple documents.

https://github.com/microsoft/PSRule/blob/fb29b622bf555dc29af4d522df482d68e43ac043/src/PSRule/Host/HostHelper.cs#L235-L268

This is how the default serializer is implemented.

https://github.com/aaubry/YamlDotNet/blob/baa5b661d9bbc4054d6c1bbe177587dac5150171/YamlDotNet/Serialization/Serializer.cs#L133-L142

I think that a Yaml converter will be too far down the stack to serialize multiple documentation.

ArmaanMcleod commented 2 years ago

@BernieWhite Making a custom ISerializer sounds interesting.

I also tried doing it via brute force with a baseline converter and was able to get the following:

- -
  # Default baseline for Azure rules.
    apiVersion: github.com/microsoft/PSRule/v1
    kind: Baseline
    metadata:
      annotations: {}
      name: Azure.Default
      tags: {}
    spec:
      binding: {}
      configuration: {}
      convention: {}
      rule:
        tag:
          release: GA
  -
  # Includes Azure features in preview.
    apiVersion: github.com/microsoft/PSRule/v1
    kind: Baseline
    metadata:
      annotations: {}
      name: Azure.Preview
      tags: {}
    spec:
      binding: {}
      configuration: {}
      convention: {}
      rule:
        tag:
          release:
          - GA
          - preview
  -
  # Includes all Azure rules.
    apiVersion: github.com/microsoft/PSRule/v1
    kind: Baseline
    metadata:
      annotations: {}
      name: Azure.All
      tags: {}
    spec:
      binding: {}
      configuration: {}
      convention: {}
      rule:
        tag: {}
  -
  # Include rules released June 2020 or prior for Azure GA features.
    apiVersion: github.com/microsoft/PSRule/v1
    kind: Baseline
    metadata:
      annotations:
        obsolete: true
      name: Azure.GA_2020_06
      tags: {}
    spec:
      binding: {}
      configuration: {}
      convention: {}
      rule:
        tag:
          release: GA
          ruleSet:
          - 2020_06
  -
  # Include rules released September 2020 or prior for Azure GA features.
    apiVersion: github.com/microsoft/PSRule/v1
    kind: Baseline
    metadata:
      annotations:
        obsolete: true
      name: Azure.GA_2020_09
      tags: {}
    spec:
      binding: {}
      configuration: {}
      convention: {}
      rule:
        tag:
          release: GA
          ruleSet:
          - 2020_06
          - 2020_09
  -
  # Include rules released December 2020 or prior for Azure GA features.
    apiVersion: github.com/microsoft/PSRule/v1
    kind: Baseline
    metadata:
      annotations:
        obsolete: true
      name: Azure.GA_2020_12
      tags: {}
    spec:
      binding: {}
      configuration: {}
      convention: {}
      rule:
        tag:
          release: GA
          ruleSet:
          - 2020_06
          - 2020_09
          - 2020_12
  -
  # Include rules released March 2021 or prior for Azure GA features.
    apiVersion: github.com/microsoft/PSRule/v1
    kind: Baseline
    metadata:
      annotations:
        obsolete: true
      name: Azure.GA_2021_03
      tags: {}
    spec:
      binding: {}
      configuration: {}
      convention: {}
      rule:
        tag:
          release: GA
          ruleSet:
          - 2020_06
          - 2020_09
          - 2020_12
          - 2021_03
  -
  # Include rules released June 2021 or prior for Azure GA features.
    apiVersion: github.com/microsoft/PSRule/v1
    kind: Baseline
    metadata:
      annotations:
        obsolete: true
      name: Azure.GA_2021_06
      tags: {}
    spec:
      binding: {}
      configuration: {}
      convention: {}
      rule:
        tag:
          release: GA
          ruleSet:
          - 2020_06
          - 2020_09
          - 2020_12
          - 2021_03
          - 2021_06
  -
  # Include rules released September 2021 or prior for Azure GA features.
    apiVersion: github.com/microsoft/PSRule/v1
    kind: Baseline
    metadata:
      annotations: {}
      name: Azure.GA_2021_09
      tags: {}
    spec:
      binding: {}
      configuration: {}
      convention: {}
      rule:
        tag:
          release: GA
          ruleSet:
          - 2020_06
          - 2020_09
          - 2020_12
          - 2021_03
          - 2021_06
          - 2021_09

Although this means my converter is doing alot of work 😄 . I've also noticed that there seems to be alot of inconsistency with indentation from the serializer.

I think I will explore how to do this with an ISerialiazer that handles serializing documents. I'm assuming that this will add --- between baselines as well. Does seem like that approach will get quite complicated however.

BernieWhite commented 2 years ago

@ArmaanMcleod Nice. Yes indenting is very problematic for YAML if it's not consistent.

I like the synopsis comments you have. Just need to prefix with Synopsis:.

See https://github.com/Azure/PSRule.Rules.Azure/blob/34c4c5fc5e01f9a6a9924d7f2d3102724f40a222/src/PSRule.Rules.Azure/rules/Baseline.Rule.yaml#L9

ArmaanMcleod commented 2 years ago

@BernieWhite Do you think it would be easier to just add OutputFormat and OutputEncoding options to Get-PSRuleBaseline?

I could create a separate Export-PSRuleBaseline cmdlet, but that will just have a lot of crossover functionality with Get-PSRuleBaseline.

BernieWhite commented 2 years ago

@ArmaanMcleod You have a point but I think we should use a verb that indicates the intent.

Export-PSRuleBaseline would need to have a -OutputPath to save to disk. Adding an -OutputEncoding is a good idea.

BernieWhite commented 2 years ago

Currently export in YAML is only possible. I'd like to add export to JSON later once JSON based resources are available. (#833)