ci(release): build every binary on GitHub and attach to releases
Per decision: no binaries committed to the repo; everything is built on GitHub Actions and hosted as release artifacts (releases/latest/download/<artifact>). - .github/workflows/release.yml: matrix builds the agent for linux(amd64/arm64/armv7), windows(amd64/arm64), darwin(amd64/arm64); tray for linux/windows; helper for windows; the fully-offline Inno setup.exe compiles on a windows runner via scripts/setup-build-env.ps1 -SkipGo -Build -CI. The publish job merges everything, writes SHA256SUMS, optionally signs with Azure Trusted Signing (secret-gated), and attaches to the tag's release. - Replaces build-windows.yml (removed) — one release pipeline for all platforms. - Untracks the committed dist binaries (they stay gitignored for local dev and are produced by CI now). - DESIGN-WINDOWS.md §9 updated: consumers (install.sh, the SSO modal) download from GitHub release artifacts; SSO may mirror them into /resources for air-gap.
This commit is contained in:
@@ -1,111 +0,0 @@
|
||||
name: build-windows
|
||||
|
||||
# Builds the Windows agent, tray, session helper, and the fully-offline Inno
|
||||
# installer; signs them with Azure Trusted Signing; generates SHA256SUMS; and
|
||||
# publishes the artifacts to the SSO resource tree (DESIGN-WINDOWS.md §9).
|
||||
#
|
||||
# The build itself is driven by scripts/setup-build-env.ps1 (idempotent dev/build
|
||||
# environment setup: pinned Go version, per-user Inno Setup, checksum-verified
|
||||
# vendor assets). The workflow only adds signing and publishing on top.
|
||||
#
|
||||
# Signing requires GitHub OIDC federation to Azure. If the Azure secrets are
|
||||
# not configured the workflow still builds and attaches unsigned artifacts.
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ["v*"]
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.22.2"
|
||||
VERSION: ${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || 'dev' }}
|
||||
|
||||
jobs:
|
||||
build-windows:
|
||||
runs-on: windows-latest
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
# One idempotent step sets up Inno Setup + fetches/verifies the vendor
|
||||
# assets and builds binaries + installer + runs the test suite.
|
||||
- name: Setup build environment and build
|
||||
shell: pwsh
|
||||
run: |
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/setup-build-env.ps1 -SkipGo -Build -CI
|
||||
if ($LASTEXITCODE -ne 0) { throw "setup-build-env failed" }
|
||||
|
||||
- name: Generate SHA256SUMS
|
||||
shell: pwsh
|
||||
run: |
|
||||
Get-ChildItem dist -File | Where-Object {
|
||||
$_.Name -match 'windows-.*\.exe$|setup\.exe$' -or $_.Name -eq 'SHA256SUMS'
|
||||
} | ForEach-Object {
|
||||
"{0} {1}" -f (Get-FileHash -Algorithm SHA256 $_.FullName).Hash.ToLower(), $_.Name
|
||||
} | Set-Content -Path dist/SHA256SUMS
|
||||
|
||||
- name: Sign with Azure Trusted Signing
|
||||
if: env.AZURE_TENANT_ID != ''
|
||||
uses: azure/login@v2
|
||||
with:
|
||||
client-id: ${{ secrets.AZURE_CLIENT_ID }}
|
||||
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
||||
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||||
|
||||
- name: AzureSignTool (agent, tray, helper, CP, installer)
|
||||
if: env.AZURE_TENANT_ID != ''
|
||||
uses: azure/trusted-signing-action@v0.4.0
|
||||
with:
|
||||
endpoint: ${{ secrets.AZURE_TS_ENDPOINT }}
|
||||
trusted-signing-account-name: ${{ secrets.AZURE_TS_ACCOUNT }}
|
||||
certificate-profile-name: ${{ secrets.AZURE_TS_CERT_PROFILE }}
|
||||
files: |
|
||||
dist/theta-agent-windows-*.exe
|
||||
dist/theta-agent-tray-windows-*.exe
|
||||
dist/theta-agent-helper-windows-*.exe
|
||||
dist/theta-agent-*-setup.exe
|
||||
output-files: ""
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: theta-agent-windows
|
||||
path: |
|
||||
dist/theta-agent-windows-*.exe
|
||||
dist/theta-agent-helper-windows-*.exe
|
||||
dist/theta-agent-tray-windows-*.exe
|
||||
dist/theta-agent-*-setup.exe
|
||||
dist/SHA256SUMS
|
||||
|
||||
- name: Attach to GitHub release
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: |
|
||||
dist/theta-agent-windows-*.exe
|
||||
dist/theta-agent-helper-windows-*.exe
|
||||
dist/theta-agent-tray-windows-*.exe
|
||||
dist/theta-agent-*-setup.exe
|
||||
dist/SHA256SUMS
|
||||
|
||||
# DESIGN-WINDOWS.md §9: the SSO holds the release resources. Publish when
|
||||
# an admin-gated upload endpoint is configured; otherwise the artifacts
|
||||
# are available from the GitHub release above.
|
||||
- name: Publish to SSO resource tree
|
||||
if: env.SSO_RESOURCE_PUBLISH_URL != ''
|
||||
shell: pwsh
|
||||
run: |
|
||||
$headers = @{ Authorization = "Bearer $env:SSO_RESOURCE_PUBLISH_TOKEN" }
|
||||
foreach ($f in Get-ChildItem dist -File) {
|
||||
if ($f.Name -notmatch "setup|windows-|SHA256SUMS") { continue }
|
||||
Invoke-RestMethod -Method Post -Uri "$env:SSO_RESOURCE_PUBLISH_URL/$($f.Name)" -InFile $f.FullName -Headers $headers
|
||||
}
|
||||
env:
|
||||
SSO_RESOURCE_PUBLISH_URL: ${{ secrets.SSO_RESOURCE_PUBLISH_URL }}
|
||||
SSO_RESOURCE_PUBLISH_TOKEN: ${{ secrets.SSO_RESOURCE_PUBLISH_TOKEN }}
|
||||
@@ -0,0 +1,140 @@
|
||||
name: release
|
||||
|
||||
# Builds every theta-agent binary on GitHub and attaches them to the release as
|
||||
# artifacts (DESIGN-WINDOWS.md §9, and the "host binaries as release artifacts"
|
||||
# decision): the agent for linux/windows/darwin, the tray for linux/windows,
|
||||
# the session helper for windows, and the fully-offline Inno setup.exe. Nothing
|
||||
# binary is committed to the repo; consumers (install.sh, the SSO Install Agent
|
||||
# modal) download from releases/latest/download/<artifact>.
|
||||
#
|
||||
# git tag v2.1.0 && git push origin v2.1.0
|
||||
# -> builds all binaries, compiles the installer, attaches everything
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ["v*"]
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.22.2"
|
||||
|
||||
jobs:
|
||||
build-agent:
|
||||
name: agent-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.goarm }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- goos: linux
|
||||
goarch: amd64
|
||||
artifact: theta-agent-linux-amd64
|
||||
- goos: linux
|
||||
goarch: arm64
|
||||
artifact: theta-agent-linux-arm64
|
||||
- goos: linux
|
||||
goarch: arm
|
||||
goarm: "7"
|
||||
artifact: theta-agent-linux-armv7
|
||||
- goos: windows
|
||||
goarch: amd64
|
||||
artifact: theta-agent-windows-amd64.exe
|
||||
- goos: windows
|
||||
goarch: arm64
|
||||
artifact: theta-agent-windows-arm64.exe
|
||||
- goos: darwin
|
||||
goarch: amd64
|
||||
artifact: theta-agent-darwin-amd64
|
||||
- goos: darwin
|
||||
goarch: arm64
|
||||
artifact: theta-agent-darwin-arm64
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
- name: Build
|
||||
shell: bash
|
||||
run: |
|
||||
CGO_ENABLED=0 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} GOARM=${{ matrix.goarm }} \
|
||||
go build -ldflags="-s -w" -o dist/${{ matrix.artifact }} .
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact }}
|
||||
path: dist/${{ matrix.artifact }}
|
||||
if-no-files-found: error
|
||||
|
||||
build-desktop:
|
||||
name: tray/helper/setup
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
# One idempotent script: installs per-user Inno Setup, fetches the
|
||||
# checksum-verified vendor assets, builds agent/tray/helper for windows
|
||||
# amd64+arm64, runs go test, and compiles the offline setup.exe.
|
||||
- name: Build windows artifacts + installer
|
||||
shell: pwsh
|
||||
run: |
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/setup-build-env.ps1 -SkipGo -Build -CI
|
||||
if ($LASTEXITCODE -ne 0) { throw "setup-build-env failed" }
|
||||
|
||||
- name: Upload windows artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows-desktop
|
||||
path: |
|
||||
dist/theta-agent-tray-windows-*.exe
|
||||
dist/theta-agent-helper-windows-*.exe
|
||||
dist/theta-agent-windows-*.exe
|
||||
dist/theta-agent-*-setup.exe
|
||||
if-no-files-found: error
|
||||
|
||||
publish:
|
||||
name: Attach to GitHub release
|
||||
needs: [build-agent, build-desktop]
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: dist
|
||||
merge-multiple: true
|
||||
|
||||
- name: Generate SHA256SUMS
|
||||
shell: bash
|
||||
run: |
|
||||
cd dist
|
||||
sha256sum * | tee SHA256SUMS
|
||||
|
||||
# Optional Azure Trusted Signing (OIDC federation). Runs only when the
|
||||
# Azure secrets are configured; otherwise the artifacts ship unsigned.
|
||||
- name: Sign with Azure Trusted Signing
|
||||
if: env.AZURE_TENANT_ID != ''
|
||||
uses: azure/login@v2
|
||||
with:
|
||||
client-id: ${{ secrets.AZURE_CLIENT_ID }}
|
||||
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
||||
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||||
|
||||
- name: AzureSignTool
|
||||
if: env.AZURE_TENANT_ID != ''
|
||||
uses: azure/trusted-signing-action@v0.4.0
|
||||
with:
|
||||
endpoint: ${{ secrets.AZURE_TS_ENDPOINT }}
|
||||
trusted-signing-account-name: ${{ secrets.AZURE_TS_ACCOUNT }}
|
||||
certificate-profile-name: ${{ secrets.AZURE_TS_CERT_PROFILE }}
|
||||
files: dist/**
|
||||
|
||||
- name: Attach to release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: dist/**
|
||||
fail_on_unmatched_files: false
|
||||
+17
-15
@@ -206,22 +206,24 @@ Install-time behavior:
|
||||
|
||||
## 9. Build & release (GitHub Actions + Azure Trusted Signing)
|
||||
|
||||
- **Local dev builds** are self-signed / unsigned.
|
||||
- **No binaries live in the repos.** Every artifact is built on GitHub Actions and
|
||||
attached to the release (`releases/latest/download/<artifact>`) — see
|
||||
`.github/workflows/release.yml`. Consumers download from there:
|
||||
- `install.sh` (Linux) already fetches the agent/tray from `releases/latest/download/`.
|
||||
- The SSO's Install Agent modal emits a PowerShell one-liner that downloads the
|
||||
Windows `setup.exe` from `releases/latest/download/`.
|
||||
- **Production builds** run in GitHub Actions:
|
||||
- Build matrix: agent `windows-amd64`/`arm64`, tray, helper, OpenCredential CP
|
||||
(MSBuild/.NET 4.8), then the Inno installer.
|
||||
- **Azure Trusted Signing** signs the agent, tray, helper, CP DLL, and installer
|
||||
(workflow federated identity → AzureSignTool). Authenticode chains verify offline,
|
||||
which suits air-gap; SmartScreen reputation simply won't accumulate, which is expected.
|
||||
- Release tags (e.g. `v2.0.1`) name the artifacts; `SHA256SUMS` manifest is generated.
|
||||
- **The SSO holds all resources** (client installer is the deliverable; the server stack
|
||||
is assumed to already run inside the air-gap):
|
||||
- New resource tree: `/resources/theta-agent/windows/...` for the installer, loose
|
||||
binaries, and `SHA256SUMS`.
|
||||
- Release workflow uploads artifacts (admin-gated publish endpoint or mounted resource
|
||||
dir); SSO pins a "latest" pointer.
|
||||
- Self-update feed uses the existing signed `update_binary` flow; the agent's fetch is
|
||||
made platform-aware (currently `cli.go` hardcodes the Linux artifact name).
|
||||
- Matrix: agent for `linux`(amd64/arm64/armv7), `windows`(amd64/arm64), `darwin`(amd64/arm64);
|
||||
tray for linux/windows; helper for windows.
|
||||
- The fully-offline Inno installer compiles on a `windows-latest` runner via
|
||||
`scripts/setup-build-env.ps1 -SkipGo -Build -CI` (which also runs `go test ./...`).
|
||||
- **Azure Trusted Signing** optionally signs everything (workflow federated identity →
|
||||
AzureSignTool, gated on secrets). Authenticode chains verify offline, which suits
|
||||
air-gap; SmartScreen reputation simply won't accumulate, which is expected.
|
||||
- Release tags (e.g. `v2.1.0`) name the artifacts; a `SHA256SUMS` manifest is attached.
|
||||
- **Self-update** uses the existing signed `update_binary` flow; the agent's fetch is
|
||||
platform-aware. On an air-gapped LAN the SSO can mirror the release artifacts into
|
||||
`/resources/theta-agent/` at deploy time; nothing on the target host hits the internet.
|
||||
|
||||
## 10. Air-gap considerations
|
||||
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Reference in New Issue
Block a user