Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions .github/workflows/publish-cli-runtime-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ on:
paths:
- tools/cli-runtime/Dockerfile
- scripts/Invoke-CdevCli.ps1
- scripts/Write-CliDependencyAttestation.ps1
- scripts/lib/**
- cli-contract.json

Expand Down Expand Up @@ -102,6 +103,57 @@ jobs:
push: true
tags: ${{ steps.resolve.outputs.tags }}

- name: Capture fork/upstream sync evidence
id: sync_guard
continue-on-error: true
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
$ErrorActionPreference = 'Stop'
$syncReportPath = Join-Path $env:RUNNER_TEMP 'fork-upstream-sync-drift-report.json'
& pwsh -NoProfile -File ./scripts/Test-ForkUpstreamSyncGuard.ps1 `
-UpstreamRepository 'LabVIEW-Community-CI-CD/labview-cdev-cli' `
-ForkRepository 'svelderrainruiz/labview-cdev-cli' `
-UpstreamBranch 'main' `
-ForkBranch 'main' `
-OutputPath $syncReportPath

- name: Write CLI dependency attestation
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
$syncReportPath = Join-Path $env:RUNNER_TEMP 'fork-upstream-sync-drift-report.json'
$attestationPath = Join-Path $env:RUNNER_TEMP 'cli-dependency-attestation.json'

$syncReportArgs = @()
if (Test-Path -LiteralPath $syncReportPath -PathType Leaf) {
$syncReportArgs = @('-SyncGuardReportPath', $syncReportPath)
}

& pwsh -NoProfile -File ./scripts/Write-CliDependencyAttestation.ps1 `
-SourceCommit '${{ github.sha }}' `
-RuntimeImageRepository '${{ steps.resolve.outputs.image_repo }}' `
-RuntimeImageDigest '${{ steps.build.outputs.digest }}' `
-OutputPath $attestationPath `
@syncReportArgs

- name: Upload sync-guard evidence report
if: always()
uses: actions/upload-artifact@v4
with:
name: fork-upstream-sync-drift-report
path: ${{ runner.temp }}/fork-upstream-sync-drift-report.json
if-no-files-found: warn

- name: Upload CLI dependency attestation
if: always()
uses: actions/upload-artifact@v4
with:
name: cli-dependency-attestation
path: ${{ runner.temp }}/cli-dependency-attestation.json
if-no-files-found: error

- name: Publish summary
shell: bash
run: |
Expand All @@ -111,6 +163,7 @@ jobs:
echo "- Image: \`${{ steps.resolve.outputs.image_repo }}\`"
echo "- Digest: \`${{ steps.build.outputs.digest }}\`"
echo "- Commit: \`${GITHUB_SHA}\`"
echo "- Dependency attestation: \`cli-dependency-attestation.json\`"
echo "- Tags:"
while IFS= read -r tag; do
echo " - \`$tag\`"
Expand Down
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,19 @@ This repository is the control-plane CLI for deterministic `C:\dev` workspace or
- installer iterations (`installer exercise`)
- post-action gate summaries (`postactions collect`)
- Linux NI deploy checks (`linux deploy-ni`).
- release program orchestration (`ops program run|status|freeze|unfreeze|drill|evidence export`).
- Core command tokens that must stay stable:
- `Invoke-CdevCli.ps1`
- `repos doctor`
- `installer exercise`
- `postactions collect`
- `linux deploy-ni`
- `ops program run`
- `ops program status`
- `ops program freeze`
- `ops program unfreeze`
- `ops program drill`
- `ops program evidence export`
- `desktop-linux`
- `nationalinstruments/labview:latest-linux`

Expand Down Expand Up @@ -83,3 +90,4 @@ This repository is the control-plane CLI for deterministic `C:\dev` workspace or
- `cdev-cli.slsa.json`
- `publish-cli-runtime-image.yml` publishes base runtime image `ghcr.io/<repository-owner>/labview-cdev-cli-runtime` with immutable tags (`sha-*`, `v1-YYYYMMDD`) and optional mutable `v1`.
- Canonical consumer image path is `ghcr.io/labview-community-ci-cd/labview-cdev-cli-runtime`.
- `publish-cli-runtime-image.yml` must upload `cli-dependency-attestation.json` with runtime digest + sync-guard/parity evidence.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ On Linux, invoke the same entrypoint with `pwsh -NoProfile -File`.
- `linux install`
- `linux deploy-ni`
- `ci integration-gate`
- `ops program run`
- `ops program status`
- `ops program freeze`
- `ops program unfreeze`
- `ops program drill`
- `ops program evidence export`
- `release package`

## Quick Start
Expand All @@ -32,6 +38,7 @@ powershell -NoProfile -ExecutionPolicy RemoteSigned -File .\scripts\Invoke-CdevC
powershell -NoProfile -ExecutionPolicy RemoteSigned -File .\scripts\Invoke-CdevCli.ps1 repos doctor --workspace-root C:\dev
powershell -NoProfile -ExecutionPolicy RemoteSigned -File .\scripts\Invoke-CdevCli.ps1 installer exercise --mode fast --iterations 1
powershell -NoProfile -ExecutionPolicy RemoteSigned -File .\scripts\Invoke-CdevCli.ps1 ci integration-gate --repo svelderrainruiz/labview-cdev-surface --branch main
powershell -NoProfile -ExecutionPolicy RemoteSigned -File .\scripts\Invoke-CdevCli.ps1 ops program run --mode Validate --dry-run true --enrollment-repo LabVIEW-Community-CI-CD/labview-cdev-surface-fork
```

## Linux Flow (Docker Desktop Linux)
Expand Down Expand Up @@ -67,6 +74,14 @@ Deterministic tags:
- `v1-YYYYMMDD`
- `v1` (when promoted)

The publish workflow also emits:
- `cli-dependency-attestation.json`
- `source_commit`
- `runtime_image.repository`
- `runtime_image.digest`
- `sync_guard_evidence`
- `parity_evidence`

Dispatch manually:

```powershell
Expand Down
8 changes: 8 additions & 0 deletions cli-contract.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@
"postactions": ["collect"],
"linux": ["install", "deploy-ni"],
"ci": ["integration-gate"],
"ops": [
"program run",
"program status",
"program freeze",
"program unfreeze",
"program drill",
"program evidence export"
],
"release": ["package"]
}
}
61 changes: 60 additions & 1 deletion scripts/Invoke-CdevCli.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ foreach ($libFile in @(
'Installer.Commands.ps1',
'Linux.Commands.ps1',
'Ci.Commands.ps1',
'OpsProgram.Commands.ps1',
'Release.Commands.ps1'
)) {
$path = Join-Path $libRoot $libFile
Expand Down Expand Up @@ -62,6 +63,12 @@ function Show-CdevHelp {
' linux install',
' linux deploy-ni',
' ci integration-gate',
' ops program run',
' ops program status',
' ops program freeze',
' ops program unfreeze',
' ops program drill',
' ops program evidence export',
' release package',
'',
'Examples:',
Expand All @@ -70,7 +77,8 @@ function Show-CdevHelp {
' powershell -NoProfile -ExecutionPolicy RemoteSigned -File scripts/Invoke-CdevCli.ps1 installer exercise --mode fast --iterations 1',
' powershell -NoProfile -ExecutionPolicy RemoteSigned -File scripts/Invoke-CdevCli.ps1 postactions collect --report-path C:\dev\artifacts\workspace-install-latest.json',
' powershell -NoProfile -ExecutionPolicy RemoteSigned -File scripts/Invoke-CdevCli.ps1 linux install --workspace-root C:\dev-linux',
' powershell -NoProfile -ExecutionPolicy RemoteSigned -File scripts/Invoke-CdevCli.ps1 linux deploy-ni --workspace-root C:\dev-linux --docker-context desktop-linux'
' powershell -NoProfile -ExecutionPolicy RemoteSigned -File scripts/Invoke-CdevCli.ps1 linux deploy-ni --workspace-root C:\dev-linux --docker-context desktop-linux',
' powershell -NoProfile -ExecutionPolicy RemoteSigned -File scripts/Invoke-CdevCli.ps1 ops program run --mode Validate --dry-run true --enrollment-repo LabVIEW-Community-CI-CD/labview-cdev-surface-fork'
)

if ([string]::IsNullOrWhiteSpace($Topic)) {
Expand All @@ -84,6 +92,7 @@ function Show-CdevHelp {
'postactions' { Write-Host 'postactions command: collect' }
'linux' { Write-Host 'linux commands: install, deploy-ni' }
'ci' { Write-Host 'ci command: integration-gate' }
'ops' { Write-Host 'ops commands: program run|status|freeze|unfreeze|drill|evidence export' }
'release' { Write-Host 'release command: package' }
default {
Write-Host "Unknown help topic '$Topic'."
Expand Down Expand Up @@ -205,6 +214,56 @@ try {
}
}
}
'ops' {
switch ($command) {
'program' {
if ($passThroughArgs.Count -lt 1) {
throw "Unsupported ops program command ''. Use 'ops program run|status|freeze|unfreeze|drill|evidence export'."
}

$programAction = ([string]$passThroughArgs[0]).ToLowerInvariant()
$programArgs = if ($passThroughArgs.Count -gt 1) { @($passThroughArgs[1..($passThroughArgs.Count - 1)]) } else { @() }
switch ($programAction) {
'run' {
$result = Invoke-CdevOpsProgramRun -PassThroughArgs $programArgs
}
'status' {
$result = Invoke-CdevOpsProgramStatus -PassThroughArgs $programArgs
}
'freeze' {
$result = Invoke-CdevOpsProgramFreeze -PassThroughArgs $programArgs
}
'unfreeze' {
$result = Invoke-CdevOpsProgramUnfreeze -PassThroughArgs $programArgs
}
'drill' {
$result = Invoke-CdevOpsProgramDrill -PassThroughArgs $programArgs
}
'evidence' {
if ($programArgs.Count -lt 1) {
throw "Unsupported ops program evidence subcommand ''. Use 'ops program evidence export'."
}
$evidenceAction = ([string]$programArgs[0]).ToLowerInvariant()
$evidenceArgs = if ($programArgs.Count -gt 1) { @($programArgs[1..($programArgs.Count - 1)]) } else { @() }
switch ($evidenceAction) {
'export' {
$result = Invoke-CdevOpsProgramEvidenceExport -PassThroughArgs $evidenceArgs
}
default {
throw "Unsupported ops program evidence subcommand '$evidenceAction'. Use 'ops program evidence export'."
}
}
}
default {
throw "Unsupported ops program command '$programAction'. Use 'ops program run|status|freeze|unfreeze|drill|evidence export'."
}
}
}
default {
throw "Unsupported ops command '$command'. Use 'ops program ...'."
}
}
}
'release' {
switch ($command) {
'package' {
Expand Down
Loading