microsoft/hve-core

Public

mirrored fromhttps://github.com/microsoft/hve-coreAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
feat/886-python-lint-fix

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

scripts/security/Sign-PlannerArtifacts.ps1

199lines ยท modecode

1#!/usr/bin/env pwsh
2# Copyright (c) Microsoft Corporation.
3# SPDX-License-Identifier: MIT
4
5#Requires -Version 7.0
6
7<#
8.SYNOPSIS
9 Generates a SHA-256 manifest for RAI planning artifacts and optionally signs it with cosign.
10
11.DESCRIPTION
12 Enumerates all files under the RAI planning artifact directory for a given project slug,
13 computes SHA-256 hashes for each artifact, and writes a JSON manifest file. When cosign
14 is available and requested, the manifest is signed using Sigstore keyless signing to
15 provide cryptographic provenance.
16
17.PARAMETER ProjectSlug
18 The project slug identifying the RAI planning session. Corresponds to the subdirectory
19 under .copilot-tracking/rai-plans/.
20
21.PARAMETER OutputPath
22 Path for the generated manifest file. Defaults to
23 .copilot-tracking/rai-plans/{ProjectSlug}/artifact-manifest.json.
24
25.PARAMETER IncludeCosign
26 When specified, attempts to sign the manifest with cosign keyless signing after
27 generation. Requires cosign to be available in PATH. Gracefully skips signing with
28 a warning when cosign is not found.
29
30.EXAMPLE
31 ./scripts/security/Sign-PlannerArtifacts.ps1 -ProjectSlug "contoso-ai"
32
33 Generates a SHA-256 manifest for all artifacts under
34 .copilot-tracking/rai-plans/contoso-ai/.
35
36.EXAMPLE
37 ./scripts/security/Sign-PlannerArtifacts.ps1 -ProjectSlug "contoso-ai" -IncludeCosign
38
39 Generates the manifest and signs it with cosign keyless signing.
40
41.EXAMPLE
42 npm run rai:sign -- -ProjectSlug "contoso-ai" -IncludeCosign
43
44 Invokes the script through the npm wrapper with cosign signing enabled.
45
46.NOTES
47 The manifest excludes its own file (artifact-manifest.json) and any cosign signature
48 files (.sig, .bundle) from the hash inventory to avoid circular references.
49#>
50
51[CmdletBinding()]
52param(
53 [Parameter(Mandatory)]
54 [ValidateNotNullOrEmpty()]
55 [string]$ProjectSlug,
56
57 [Parameter(Mandatory = $false)]
58 [string]$OutputPath,
59
60 [Parameter(Mandatory = $false)]
61 [switch]$IncludeCosign
62)
63
64$ErrorActionPreference = 'Stop'
65
66#region Helper Functions
67
68function Get-ArtifactHash {
69 <#
70 .SYNOPSIS
71 Computes the SHA-256 hash of a file and returns a lowercase hex string.
72 .OUTPUTS
73 [string] Lowercase hex SHA-256 digest.
74 #>
75 [CmdletBinding()]
76 [OutputType([string])]
77 param(
78 [Parameter(Mandatory)]
79 [string]$FilePath
80 )
81
82 (Get-FileHash -Path $FilePath -Algorithm SHA256).Hash.ToLower()
83}
84
85#endregion Helper Functions
86
87#region Main Execution
88if ($MyInvocation.InvocationName -ne '.') {
89 try {
90 #region Artifact Generation
91
92 $repoRoot = & git rev-parse --show-toplevel 2>$null
93 if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($repoRoot)) {
94 $repoRoot = $PWD.Path
95 }
96 $artifactDir = Join-Path -Path $repoRoot -ChildPath ".copilot-tracking/rai-plans/$ProjectSlug"
97
98 if (-not (Test-Path -Path $artifactDir -PathType Container)) {
99 Write-Host "โŒ Artifact directory not found: $artifactDir" -ForegroundColor Red
100 exit 1
101 }
102
103 if (-not $OutputPath) {
104 $OutputPath = Join-Path -Path $artifactDir -ChildPath 'artifact-manifest.json'
105 }
106
107 # File patterns to exclude from the manifest to avoid circular references
108 $excludePatterns = @(
109 'artifact-manifest.json',
110 '*.sig',
111 '*.bundle'
112 )
113
114 Write-Host "๐Ÿ” Generating artifact manifest for project: $ProjectSlug" -ForegroundColor Cyan
115
116 $artifacts = Get-ChildItem -Path $artifactDir -File -Recurse |
117 Where-Object {
118 $fileName = $_.Name
119 -not ($excludePatterns | Where-Object { $fileName -like $_ })
120 } |
121 Sort-Object FullName
122
123 if ($artifacts.Count -eq 0) {
124 Write-Host "โš ๏ธ No artifacts found in: $artifactDir" -ForegroundColor Yellow
125 exit 0
126 }
127
128 Write-Host "๐Ÿ“ Found $($artifacts.Count) artifact(s) to hash" -ForegroundColor Cyan
129
130 $fileEntries = [System.Collections.Generic.List[object]]::new()
131
132 foreach ($file in $artifacts) {
133 $relativePath = $file.FullName.Substring($artifactDir.Length + 1) -replace '\\', '/'
134 $hash = Get-ArtifactHash -FilePath $file.FullName
135 $fileEntries.Add(@{
136 path = $relativePath
137 sha256 = $hash
138 sizeBytes = $file.Length
139 })
140 Write-Host " โœ… $relativePath" -ForegroundColor Green
141 }
142
143 $manifest = [ordered]@{
144 version = '1.0'
145 projectSlug = $ProjectSlug
146 generatedAt = [DateTime]::UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ")
147 algorithm = 'SHA256'
148 fileCount = $fileEntries.Count
149 artifacts = $fileEntries.ToArray()
150 }
151
152 $manifestJson = $manifest | ConvertTo-Json -Depth 10
153 Set-Content -Path $OutputPath -Value $manifestJson -Encoding utf8NoBOM
154
155 Write-Host "๐Ÿ“‹ Manifest written to: $OutputPath" -ForegroundColor Green
156 Write-Host " Files hashed: $($fileEntries.Count)" -ForegroundColor Cyan
157
158 #endregion Artifact Generation
159
160 #region Cosign Signing
161
162 if ($IncludeCosign) {
163 $cosignCmd = Get-Command -Name 'cosign' -ErrorAction SilentlyContinue
164
165 if (-not $cosignCmd) {
166 Write-Host "โš ๏ธ cosign not found in PATH. Skipping signature." -ForegroundColor Yellow
167 Write-Host " Install cosign from https://docs.sigstore.dev/cosign/system_config/installation/" -ForegroundColor Yellow
168 exit 0
169 }
170
171 Write-Host "๐Ÿ” Signing manifest with cosign keyless signing..." -ForegroundColor Cyan
172
173 try {
174 & cosign sign-blob `
175 --yes `
176 --output-signature "$OutputPath.sig" `
177 --bundle "$OutputPath.bundle" `
178 $OutputPath
179
180 Write-Host "โœ… Manifest signed successfully" -ForegroundColor Green
181 Write-Host " Signature: $OutputPath.sig" -ForegroundColor Cyan
182 Write-Host " Bundle: $OutputPath.bundle" -ForegroundColor Cyan
183 }
184 catch {
185 Write-Host "โŒ Cosign signing failed: $_" -ForegroundColor Red
186 exit 2
187 }
188 }
189
190 #endregion Cosign Signing
191
192 Write-Host "๐ŸŽ‰ Artifact signing complete" -ForegroundColor Green
193 }
194 catch {
195 Write-Error "Sign-PlannerArtifacts failed: $($_.Exception.Message)" -ErrorAction Continue
196 exit 1
197 }
198}
199#endregion Main Execution
200