Skip to content

Improve logging in the UfwStatus procedure #3712

Improve logging in the UfwStatus procedure

Improve logging in the UfwStatus procedure #3712

name: Universal NRP Test
on:
workflow_dispatch:
inputs:
policy_packages:
description: 'List of policy packages to test'
required: true
default: '[]'
pull_request:
schedule:
- cron: '0 20 * * *' # Every day at 12pm PST (UTC-8)
env:
storageAccountName: 'osconfigstorage'
storageContainerName: 'policypackages'
defaultSelfHostedImage: 'ubuntu-22.04'
vmDefaultMemory: '2048' # Default memory for local VMs in MB
jobs:
package:
name: Package
if: ${{ inputs.policy_packages == '[]' || inputs.policy_packages == '' }}
uses: ./.github/workflows/package-build.yml
needs: [setup-matrix]
secrets:
onedstenant: >-
${{
(github.ref == 'refs/heads/main' && secrets.ONEDS_TENANT_PROD) ||
(github.ref == 'refs/heads/dev' && secrets.ONEDS_TENANT_NONPROD) ||
(github.ref == 'refs/heads/ahbenmes/telemetry_staging' && secrets.ONEDS_TENANT_NONPROD) ||
''
}}
with:
target: ubuntu-14.04
arch: amd64
artifact: nrp-test
package-type: DEB
container-tag: "@sha256:d6f9c8072541d23779b0fbd4ff53d7b55dbdcf5d8998aa44a790546d9ec1e747"
test: true
machine-config: true
release: ${{ github.event_name == 'pull_request' && false || true }}
setup-matrix:
name: Setup Matrix
runs-on: ubuntu-latest
outputs:
targets: ${{ steps.matrix.outputs.targets }}
custom_download: ${{ steps.matrix.outputs.custom_download }}
policy_packages: ${{ steps.matrix.outputs.policy_packages }}
default_self_hosted_image: ${{ steps.matrix.outputs.default_self_hosted_image }}
steps:
- name: Generate Matrix
id: matrix
env:
DEFAULT_POLICYPACKAGES: |
[
{ "name": "LinuxSshServerSecurityBaseline", "short-name": "SSH", "resource-count": 20 },
{ "name": "AzureLinuxBaseline", "short-name": "ASB", "resource-count": 169 }
]
TARGETS: |
[
{ "os": "almalinux", "version": "9" },
{ "os": "azurelinux", "version": "3" },
{ "os": "debian", "version": "11" },
{ "os": "debian", "version": "12" },
{ "os": "oraclelinux", "version": "8" },
{ "os": "rhel", "version": "8" },
{ "os": "rhel", "version": "9" },
{ "os": "sles", "version": "15" },
{ "os": "ubuntu", "version": "20.04" },
{ "os": "ubuntu", "version": "22.04" },
{ "os": "ubuntu", "version": "24.04" }
]
run: |
# If no explicit packages defined, use the default packages
if [[ '${{ inputs.policy_packages }}' == '[]' || '${{ inputs.policy_packages }}' == '' ]]; then
custom_download="false"
policy_packages="$DEFAULT_POLICYPACKAGES"
else
custom_download="true"
policy_packages="${{ inputs.policy_packages }}"
fi
if policy_packages=$(echo $policy_packages | jq -r 'tostring'); then
echo "Successfully processed JSON"
else
echo "Failed to process JSON, attempting to process as raw JSON"
policy_packages=$(echo $policy_packages | jq -R -r 'tostring' | tr -d '\\')
fi
echo $custom_download
echo $policy_packages
echo targets=$(echo $TARGETS | jq -r 'tostring') >> $GITHUB_OUTPUT
echo custom_download=$custom_download >> $GITHUB_OUTPUT
echo policy_packages=$policy_packages >> $GITHUB_OUTPUT
echo default_self_hosted_image="${{ env.defaultSelfHostedImage }}" >> $GITHUB_OUTPUT
custom-download:
name: Custom Download
if: ${{ needs.setup-matrix.outputs.custom_download == 'true' }}
needs: [setup-matrix]
runs-on: [self-hosted, 1ES.Pool=ci-pool, '1ES.ImageOverride=${{ needs.setup-matrix.outputs.default_self_hosted_image }}']
steps:
- name: Check and Install Az module
shell: pwsh
run: |
Write-Host 'Checking the Az module...'
try {
Get-InstalledModule Az -AllVersions -ErrorAction Stop
Write-Host 'Az module is already installed.'
} catch {
Write-Host 'Az module is not installed. Trying to install...'
Install-Module -Name Az -Repository PSGallery -Force
}
Write-Host 'Done'
- name: Azure login
uses: azure/login@v2
with:
auth-type: IDENTITY
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
enable-AzPSSession: true
- name: Azure PowerShell script
uses: azure/powershell@v2
with:
azPSVersion: latest
inlineScript: |
# Download the policy packages from Azure Storage or from a URL
$jsonPolicyPackages = '${{ needs.setup-matrix.outputs.policy_packages }}'
$policyPackages = $jsonPolicyPackages | ConvertFrom-Json
foreach ($package in $policyPackages) {
$policyPackagUrl=$package.'policy-package-url'
$storageURIPrefix="storage://"
if ($policyPackagUrl.StartsWith($storageURIPrefix)) {
$storagePath=$policyPackagUrl.Substring($storageURIPrefix.Length)
Write-Host "Downloading $storagePath from Azure Storage"
$storageContext = New-AzStorageContext -StorageAccountName $env:storageAccountName -UseConnectedAccount
Get-AzStorageBlobContent -Container $env:storageContainerName -Blob $storagePath -Context $storageContext -Destination $storagePath
} else {
Write-Host "Downloading from url \"$policyPackagUrl\""
Invoke-WebRequest -Uri $policyPackagUrl -OutFile PolicyPackage.zip
}
}
- uses: actions/upload-artifact@v4
with:
name: nrp-test
path: '*.zip'
mc-test:
name: MC Test
if: ${{ always() && needs.setup-matrix.result == 'success' && (needs.package.result == 'success' || needs.custom-download.result == 'success') }}
needs: [setup-matrix, package, custom-download]
runs-on: [self-hosted, 1ES.Pool=ci-pool, '1ES.ImageOverride=${{ matrix.target.os }}-${{ matrix.target.version }}']
strategy:
fail-fast: false
matrix:
target: ${{ fromJSON(needs.setup-matrix.outputs.targets) }}
arch: [amd64]
mode: [Audit, Remediate]
policy-package: ${{ fromJSON(needs.setup-matrix.outputs.policy_packages) }}
steps:
- uses: actions/checkout@v4
with:
submodules: false
clean: true
- uses: actions/download-artifact@v4
id: download
with:
name: nrp-test
- name: Normalize variables
id: normalize
run: |
echo name="${{ matrix.target.os }}-${{ matrix.target.version }}_${{ matrix.policy-package.short-name }}-${{ matrix.mode }}" >> $GITHUB_OUTPUT
echo dir="${{ steps.download.outputs.download-path }}" >> $GITHUB_OUTPUT
echo path="${{ steps.download.outputs.download-path }}/${{ matrix.policy-package.name }}.zip" >> $GITHUB_OUTPUT
- name: Fix policy package names
if: ${{ needs.setup-matrix.outputs.custom_download == 'true' }}
working-directory: ${{ steps.normalize.outputs.PolicyPackageDir }}
shell: pwsh
run: |
$name="${{ matrix.policy-package.name }}"
Get-ChildItem -Path $name*.zip -File | Select-Object -First 1 {
Write-Host "Renaming $($_.Name) to $name.zip"
Rename-Item -Path $_.Name -NewName "$name.zip"
}
- name: Check package size
if: success() || failure()
uses: ./.github/actions/check-size
with:
package: '${{ steps.normalize.outputs.path }}'
limit: 5000
- name: Run Guest Configuration Test
working-directory: ${{ steps.normalize.outputs.PolicyPackageDir }}
run: |
script="./universalNRPTest.ps1"
cat >$script <<EOL
Install-Module -Name GuestConfiguration -Force
Install-Module Pester -Force -SkipPublisherCheck
Import-Module Pester -Passthru
\$params = @{
PolicyPackage = '${{ steps.normalize.outputs.path }}'
SkipRemediation = if ('${{ matrix.mode }}' -eq 'Audit') { \$true } else { \$false }
ResourceCount = ${{ matrix.policy-package.resource-count }}
}
\$container = New-PesterContainer -Path ./src/tests/universal-nrp-e2e/UniversalNRP.Tests.ps1 -Data \$params
\$pesterConfig = [PesterConfiguration]@{
Run = @{
Exit = \$true
Container = \$container
}
Output = @{
Verbosity = 'Detailed'
}
TestResult = @{
Enabled = \$true
OutputFormat = 'JUnitXml'
OutputPath = '${{ steps.normalize.outputs.name }}-testResults.xml'
}
Should = @{
ErrorAction = 'Continue'
}
};
Invoke-Pester -Configuration \$pesterConfig
EOL
sudo LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/omi/lib/ pwsh -Command $script
stat *testResults.xml
- name: Check performance
if: success() || failure()
uses: ./.github/actions/check-perf
with:
perflog: /var/log/osconfig_asb_perf.log
mark: "is longer than"
- name: Stage OSConfig Logs
if: success() || failure()
run: |
mkdir osconfig-logs
stat /var/log/osconfig_nrp.log
sudo chown -R $USER:$(id -gn) /var/log/osconfig*
sudo chmod 644 /var/log/osconfig*
cp -r /var/log/osconfig* osconfig-logs/
- uses: actions/upload-artifact@v4
if: success() || failure()
with:
name: ${{ steps.normalize.outputs.name }}_report
path: '${{ steps.normalize.outputs.dir }}/*testResults.xml'
- uses: actions/upload-artifact@v4
if: success() || failure()
with:
name: ${{ steps.normalize.outputs.name }}_logs
path: osconfig-logs/osconfig*
module-test:
name: Module Test
# Module test requires the package artifact as it also includes the modules to be tested in the artifact
if: ${{ needs.setup-matrix.outputs.custom_download == 'false' }}
needs: [setup-matrix, package]
runs-on: [self-hosted, 1ES.Pool=ci-pool, '1ES.ImageOverride=${{ matrix.target.os }}-${{ matrix.target.version }}']
strategy:
fail-fast: false
matrix:
target: ${{ fromJSON(needs.setup-matrix.outputs.targets) }}
arch: [amd64]
steps:
- uses: actions/checkout@v4
- run: ldd --version
- uses: actions/download-artifact@v4
id: download
with:
name: nrp-test
- name: Create osconfig.json
run: |
sudo mkdir -p /etc/osconfig
sudo cp -r ${{ steps.download.outputs.download-path }}/modules/test/osconfig.json /etc/osconfig/osconfig.json
- name: Defer test execution
uses: ./.github/actions/defer-tests
- name: Run moduletest
working-directory: ${{ steps.download.outputs.download-path }}/modules/test
run: |
sudo chmod +x ./moduletest
result=0
recipe="./recipes/SecurityBaselineTests.json"
name=$(basename $recipe | tr '[:upper:]' '[:lower:]' | sed 's/\.[^.]*$//' | sed 's/\(test\|tests\)$//')
echo -n "testing $name ... "
if output=$(sudo ./moduletest $recipe --bin ../bin); then
echo passed
else
echo failed
result=1
echo "::warning file=$name.log::Error(s) in module-test for '$name'"
fi
echo "$output"
echo "$output" > ../../$name.log
exit $result
- name: Check performance
if: success() || failure()
uses: ./.github/actions/check-perf
with:
perflog: /var/log/osconfig_asb_perf.log
mark: "is longer than"
- uses: actions/upload-artifact@v4
if: success() || failure()
with:
name: ${{ matrix.target.os }}-${{ matrix.target.version }}_logs
path: '*.log'
local-tests:
name: Local Tests
if: ${{ needs.setup-matrix.outputs.custom_download == 'false' }}
needs: package
runs-on: [self-hosted, 1ES.Pool=ci-pool, '1ES.ImageOverride=ubuntu-24.04']
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
id: download
with:
name: nrp-test
- uses: azure/login@v2
with:
auth-type: IDENTITY
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Run Local Tests
working-directory: src/tests/universal-nrp-e2e
run: |
echo "Copying Azure CLI configuration/tokens to root"
sudo mkdir -p /root/.azure
sudo cp -r ~/.azure/* /root/.azure/
echo "Starting local tests"
# Start tests using built packages, use 2048MB of memory per VM and disable the GUI
# The -n flag disables the GUI, which is needed in the headless environment
# The -p flag disables parallel image downloads
sudo ./StartTests.sh -d ${{ steps.download.outputs.download-path }} -m ${{ env.vmDefaultMemory }} -n -p
- name: Stage logs and reports
if: success() || failure()
working-directory: src/tests/universal-nrp-e2e
run: |
mkdir -p staging/reports
mkdir -p staging/logs
sudo find .cache -type f -name '*.tar.gz' | while read -r file; do
parent_dir=$(dirname "$file")
base_dir=$(basename "$parent_dir")
dest_dir="staging/reports/$base_dir"
mkdir -p "$dest_dir"
sudo cp "$file" "$dest_dir/"
pushd "$dest_dir"
sudo find . -name '*.tar.gz' -exec tar -xzf {} \; -exec rm -f {} \;
sudo find . -mindepth 2 -type f -exec mv -t . -- {} +
sudo find . -mindepth 1 -type d -exec rmdir --ignore-fail-on-non-empty {} +
sudo mkdir -p "../../logs/$base_dir"
sudo find . \( -name '*.log' -o -name '*.bak' \) -exec mv -t ../../logs/$base_dir -- {} +
popd
done
sudo chown -R $USER:$(id -gn) ./staging
echo "Listing reports:"
find ./staging/reports -type f -print | xargs ls -l
echo "Listing logs:"
find ./staging/logs -type f -print | xargs ls -l
- name: Upload Logs Artifact
uses: actions/upload-artifact@v4
if: success() || failure()
with:
name: local_tests_logs
path: 'src/tests/universal-nrp-e2e/staging/logs/**/*'
- name: Upload Test Reports Artifact
uses: actions/upload-artifact@v4
if: success() || failure()
with:
name: local_tests_reports
path: 'src/tests/universal-nrp-e2e/staging/reports/**/*testResults.xml'
- name: Cleanup root azure/login
if: always()
run: sudo rm -rf /root/.azure
# See for more details: https://github.com/marketplace/actions/publish-test-results
report:
name: Report
needs: [mc-test, local-tests]
runs-on: ubuntu-latest
permissions:
checks: write
pull-requests: write
if: always()
steps:
- name: Download CloudTest Report Artifacts
uses: actions/download-artifact@v4
with:
path: universal-nrp-test
pattern: '*_report'
merge-multiple: true
- name: Download Local Test Report Artifacts
uses: actions/download-artifact@v4
with:
path: local_tests_reports
- name: Publish CloudTest Test Results
uses: EnricoMi/publish-unit-test-result-action@v2
with:
files: 'universal-nrp-test/*testResults.xml'
- name: Publish Local Test Results
uses: EnricoMi/publish-unit-test-result-action@v2
with:
files: 'local_tests_reports/**/*testResults.xml'